[Original] .NET-based high-performance lightweight ORM - TZM.XFramework make the code more elegant

 [Introduction]

  Hello everyone, I'm TANZAME. Surprisingly, before the beginning of winter day we met again, the weather is getting cooler, friends pay attention to add clothing to keep warm, pleasant line and code. Distance TZM.XFramework  debut has more than a few months, we received a lot of friends during the encouragement, advice and feedback, in Regards to deep gratitude.

  Many onlookers often question my friend, good O / RM system have official under .NET EF, third parties have linq2db  (abroad), StackExchange / Dapper  (abroad), NHibernate  (abroad), PetaPoco  (abroad), Freesql  (domestic) and so on, What's your problem? Ok, we will go with a minute's My talk the What Advantage , talk about how to use ORM to make the code more elegant and more refreshing.

 【text】

  I believe that friends have experienced this scenario: you want to insert / delete / modify data from the foreign key table, how to do? First check out further action it took, not so old iron, database access over at least twice, is not the best approach from a performance point of view. SQL pure line and hand it looks okay at least not be so uncomfortable. If there is such a line and we can help ORM SQL, how much more happy? ORM is to look at how we operate:

  

  1. Multi association table update  

// 更新本表值等于别表的字段值
var query =
    from a in context.GetTable<Model.Client>()
    join b in context.GetTable<Model.CloudServer>() on a.CloudServerId equals b.CloudServerId
    join c in context.GetTable<Model.ClientAccount>() on a.ClientId equals c.ClientId
    where c.AccountId == "1"
    select a;
context.Update<Model.Client, Model.CloudServer, Model.ClientAccount>((a, b, c) => new
{
    CloudServerId = b.CloudServerId,
    Qty = c.Qty > 0 ? c.Qty : 1,
}, query);
context.SubmitChanges();

-- 产生的SQL
--UPDATE t0 SET
--t0.[CloudServerId] = t1.[CloudServerId],
--t0.[Qty] = (CASE WHEN t2.[Qty] > @p1 THEN t2.[Qty] ELSE @p2 END)
--FROM [Bas_Client] AS [t0]
--INNER JOIN [Sys_CloudServer] t1 ON t0.[CloudServerId] = t1.[CloudServerId]
--INNER JOIN [Bas_ClientAccount] t2 ON t0.[ClientId] = t2.[ClientId]
--WHERE t2.[AccountId] = @p3

  Carefully observe the corresponding SQL query semantics and difficult to find, from a in context.GetTable this sentence exactly corresponds to the UPDAE *** FROM TABLE this one, the next step is to associate the foreign key table that is, INNER JOIN TABLE, finally we are familiar with the WHERE clause. There is a special place that it is not Oracle UPDATE FROM this syntax, only with MERGE INTO instead. Take a look at the source code is how to achieve:

// advance resolution table alias appears in the query semantics, such as a, b, c variables expressed as t0, t1, t2 form of 
TableAliasCache this.PrepareAlias aliases = <T> (uQueryInfo.SelectInfo, token); 
ExpressionVisitorBase hit = null; 
// parse UPDATE field 
hit new new UpdateExpressionVisitor = (the this, aliases, uQueryInfo.Expression); 
visitor.Write (Builder); 
// the FROM fragment 
builder.AppendNewLine (); 
builder.append ( "the FROM"); 
Builder. AppendMember (typeRuntime.TableName, typeRuntime.IsTemporary!); 
builder.AppendAs ( "T0"); 

var = CMD2 new new MappingCommand (the this, aliases, token) = {hasMany uQueryInfo.SelectInfo.HasMany}; 
// parse the foreign key table 
visitor JoinExpressionVisitor new new = (the this, aliases, uQueryInfo.SelectInfo.Joins); 
visitor.Write (cmd2.JoinFragment);
// parsing WHERE condition
= new new WhereExpressionVisitor visitor (the this, aliases, uQueryInfo.SelectInfo.WhereExpression); 
visitor.Write (cmd2.WhereFragment); 
cmd2.AddNavMembers (visitor.NavMembers); 
// all the pieces finally merged to form the final SQL statement 
builder.Append (cmd2 .CommandText);

 

  2. Multi association table inserted

// 多表关联批量新增
var query =
    from a in context.GetTable<Model.Client>()
    join b in context.GetTable<Model.CloudServer>() on a.CloudServerId equals b.CloudServerId
    where a.ClientId <= 5 && b.CloudServerId != 0
    select new Model.Client
    {
        ClientId = DbFunction.RowNumber<int>(x => a.ClientId) + (maxClientId + 2),
        ClientCode = "ABC2",
        ClientName = "啊啵呲2",
        CloudServerId = b.CloudServerId,
        State = 2,
        ActiveDate = DateTime.Now
    };
context.Insert(query);

-- 产生的SQL
--INSERT INTO [Bas_Client]([ClientId],[ClientCode],[ClientName],[CloudServerId],[State],[ActiveDate])
--SELECT 
--ROW_NUMBER() Over(Order By t0.[ClientId]) + @p17 + @p18 AS [ClientId],
--@p19 AS [ClientCode],
--@p20 AS [ClientName],
--t1.[CloudServerId] AS [CloudServerId],
--@p21 AS [State],
--@p22 AS [ActiveDate]
--FROM [Bas_Client] t0 
--INNER JOIN [Sys_CloudServer] t1 ON t0.[CloudServerId] = t1.[CloudServerId]
--WHERE t0.[ClientId] <= @p23 AND t1.[CloudServerId] <> @p24

  As can be seen from the SQL generated to remove the first row INSERT, the rest is the entire SELECT statement, query semantics i.e. above example code query variable represents. It should be noted that the field should be recorded while parsing SELECT statement, INSERT INTO statement requires stitching over these fields. Look at the code to achieve:

// INSERT INTO 片断
builder.Append("INSERT INTO ");
builder.AppendMember(typeRuntime.TableName, !typeRuntime.IsTemporary);
builder.Append('(');

// 解析 SELECT 块
MappingCommand cmd2 = this.ParseSelectCommand(nQueryInfo.SelectInfo, 0, true, token) as MappingCommand;
int i = 0;
// 拼接 INSERT INTO 字段
foreach (Column column in cmd2.PickColumns)
{
    builder.AppendMember(column.NewName);
    if (i < cmd2.PickColumns.Count - 1) builder.Append(',');
    i++;
}
builder.Append(')');
// 最后合并所有的片断形成最终SQL语句
builder.AppendNewLine();
builder.Append(cmd2.CommandText);

  

3. Multi delete the associated table

// Query 关联批量删除
var query =
    from a in context.GetTable<Model.Client>()
    join b in context.GetTable<Model.ClientAccount>() on a.ClientId equals b.ClientId
    join c in context.GetTable<Model.ClientAccountMarket>() on new { b.ClientId, b.AccountId } equals new { c.ClientId, c.AccountId }
    where c.ClientId > 100 && c.AccountId == "1" && c.MarketId == 1
    select a;
context.Delete<Model.Client>(query1);

-- 产生的SQL
--DELETE t0 FROM [Bas_Client] t0 
--INNER JOIN [Bas_ClientAccount] t1 ON t0.[ClientId] = t1.[ClientId]
--INNER JOIN [Bas_ClientAccountMarket] t2 ON t1.[ClientId] = t2.[ClientId] AND t1.[AccountId] = t2.[AccountId]
--WHERE t2.[ClientId] > @p2 AND t2.[AccountId] = @p3 AND t2.[MarketId] = @p4 

  Delete update update with the principle is the same, nothing more than UPDATE replaced DELETE. In addition Oracle did not DELETE FROM grammar, we change a bit tricky, with the ROWID as to achieve the effect associated to delete. Finally, take a look at the code to achieve:

// DELETE FROM fragment 
builder.append ( "DELETE t0 the FROM"); 
builder.AppendMember (typeRuntime.TableName, typeRuntime.IsTemporary!); 
Builder.append ( "t0"); 
// pre-parsing table aliases, the query semantics as a, b, c which is expressed as a variable appears t0, t1, t2 form of 
TableAliasCache this.PrepareAlias aliases = <T> (dQueryInfo.SelectInfo, token); 
var = CMD2 new new MappingCommand (the this, aliases, token) {hasMany dQueryInfo.SelectInfo.HasMany} =; 
// parse the foreign key table 
ExpressionVisitorBase hit new new JoinExpressionVisitor = (the this, aliases, dQueryInfo.SelectInfo.Joins); 
visitor.Write (cmd2.JoinFragment); 
// parse WHERE condition 
visitor = new WhereExpressionVisitor ( the this, aliases, dQueryInfo.SelectInfo.WhereExpression); 
visitor.Write (cmd2.WhereFragment);
cmd2.AddNavMembers (visitor.NavMembers); 
// all the pieces finally merged to form the final SQL statement 
builder.Append (cmd2.CommandText);

    

 [Conclusion]

  Through the efforts of a large and a half months, TZM.XFramework also officially supports SQLite, and hosting Address: GitHub hosting Address: https://github.com/TANZAME/XFramework  . Finally, public borrowing above certain number of words and encourage one another, fun and curiosity to please yourself before you can be interesting and useful to please others. Yard line and not easy, not like a light spray, there are different views on the exchange of old friends welcome plus group.

  Technical exchange group: 816 425 449

  

Guess you like

Origin www.cnblogs.com/yiting/p/11823878.html