首页 > 解决方案 > 将 sql 连接脚本转换为 lambda 或 linq

问题描述

如何将此脚本转换为 lambda 或 linq ?

 select a.PayoutID,b.PayoutName 
   from [dbo].[PayoutsOfUser] a 
  inner join [dbo].[Payout] b on a.PayoutID = b.PayoutID
  inner join [dbo].[Users] c on a.UserID = c.UserID 
  where c.UserID = 16

标签: sqllinqlambda

解决方案


方法语法(= 带有 lambda 表达式的语法)比查询语法具有更多功能。因此,我更喜欢在查询语法之上使用方法语法。

但是有一个例外:当连接三个或更多表时,方法语法看起来很可怕,就像 Sebu 在他的回答中显示的那样。也显示在这个答案中,其中比较了连接三个表的两种方法

IQueryable无论是使用方法语法还是查询语法,内部的表达式都是一样的,因此生成的 SQL 语句不会有太大差异。

因此我的建议是:尽可能使用方法语法,但为了可读性、更少的错误、更好的可维护性:使用查询语法连接三个表。

如果您必须经常连接三个表,请考虑创建一个隐藏连接完成方式的扩展函数:

请参阅:扩展功能揭秘

以下函数采用三个输入序列:IQueryable、IQueryable 和 IQueryable。
它在使用 T1Join1Selector 和 T2Join1Selector 提取的键上连接前两个序列,
如果在使用 T2Join2Selector 和 T3Join2Selector 提取的键上连接后两个序列
从每个匹配的 T1 / T2 / T3 它根据 resultSelector 创建一个结果

public static IQueryable<TResult> Join<T1, T2, T3, 
    TKeyJoin1, TKeyJoin2, TResult>(
        this IQueryable<T1> table1,
        IQueryable<T2> table2,
        IQueryable<T3> table3,
        Expression<Func<T1, TKeyJoin1>> table1Join1KeySelector,
        Expression<Func<T2, TKeyJoin1>> table2Join1KeySelector,
        Expression<Func<T2, TKeyJoin2>> table2Join2KeySelector,
        Expression<Func<T3, TKeyJoin2>> table3Join2KeySelector,
        Expression<Func<T1, T2, T3, Tresult>> resultSelector)
{
     return Tabl1.Join(table2,           // join table1 and table2
     t1 => table1Join1KeySelector(t1),   // select the key from table1 for the first join
     t2 => table2Join1KeySelector(t2),   // select the key from table2 for the first join
     (t1, t2) => new                     // remember the matching records as T1 and T2
     {
          T1 = t1,
          T2 = t2,
     })

     // use this as input for the second join:
     .Join(table3,
     // use the T2 in the result of the first join as key for the second join 
     joinedT1andT2 => table2Join2KeySelector(joinedT1andT2.T2),
     t3 => table3Join2KeySelector(t3),    // select the key from table3 for the 2nd join

     // and use the result of the first and second join to create a linq-result:
     (joinedT1andT2, t3) => resultSelector(joinedT1andT2.T1, joinedT1andT2.T2, T3);
}

或者使用查询语法连接三个表:

public static IQueryable<TResult> Join<T1, T2, T3, 
    TKeyJoin1, TKeyJoin2, TResult>(
        this IQueryable<T1> table1,
        IQueryable<T2> table2,
        IQueryable<T3> table3,
        Expression<Func<T1, TKeyJoin1>> table1Join1KeySelector,
        Expression<Func<T2, TKeyJoin1>> table2Join1KeySelector,
        Expression<Func<T2, TKeyJoin2>> table2Join2KeySelector,
        Expression<Func<T3, TKeyJoin2>> table3Join2KeySelector,
        Expression<Func<T1, T2, T3, Tresult>> resultSelector)
{
    return select resultSelector(table1, table2, table3) 
    from table1 
    join table2 on table1Join1KeySelector(table1) == table2Join1KeySelector(table2)
    join table3 on table2Join2KeySelector(table2) == table3Join2KeySelector(table3) 
}

用法类似于使用方法语法连接两个表的方式:

var result = a.Join(b, c,    // join your tables a, b, c

   t1 => t1.PayoutId,        // first join on a.PayoutID = b.PayoutID
   t2 => t2.PayoutId,

   t2 => t2.UserId,          // second join on b.UserID = c.UserID 
   t3 => t3.UserId,

   (t1, t2, t3) => new       // from the matching records create one new object
   {
        PayoutId = t1.PayoutId,
        PayoutName = t2.PayoutName,
        ...
   });

我看到您的第二次加入是在 a 和 c 上,而我的第二次加入是在 b 和 c 上。我相信您会知道如何根据需要重写代码

由于此函数的结果是一个 IQueryable,因此该函数只会更改 Expression。查询尚未执行。因此,您可以安全地将其与其他 IQueryable 函数混合使用:

var resultQuery = a.Where(t1 => t1.Name = ...)
    .Join( /* 3-table join as described above */ )
    .GroupBy(joinResult => ...)
    .Take(4);

查询仍未执行,直到您执行不返回 的操作IQueryable,例如ToList// FirstOrDefault/ Any...


推荐阅读