【问题标题】:convert sql join script to lambda or linq将 sql 连接脚本转换为 lambda 或 linq
【发布时间】:2018-12-03 18:33:42
【问题描述】:

如何将此脚本转换为 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

【问题讨论】:

  • 请向我们展示您到目前为止所做的尝试。

标签: sql linq lambda


【解决方案1】:

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

但是有一个例外:当连接三个或更多表时,方法语法看起来很可怕,就像 Sebu 在他的回答中显示的那样。也显示在this answer where the two methods for joining three tables are compared

IQueryable 内部的 Expression 是一样的,不管你是使用方法语法还是查询语法,所以生成的 SQL 语句不会有太大差异。

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

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

见:extension functions demystified

以下函数采用三个输入序列: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 / ...

【讨论】:

    【解决方案2】:
    var result= PayoutsOfUser.Join(Payout,
                  a=>a.PayoutID,
                  b=>b.PayoutID,
                  (a,b)=>new{PayoutsOfUser=a,Payout=b})
                .Join(Users,
                  a=>a.PayoutsOfUser.UserID,
                  c=>c.UserID,
                  (a,c)=>new{a.PayoutsOfUser,a.Payout,Users=c})
                .Where(x=>x.Users.UserID==16)
                .Select(x=>new
                {
                     a.PayoutID,
                     b.PayoutName
                }).ToList();
    

    【讨论】:

      猜你喜欢
      • 2018-09-23
      • 2020-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多