LINQ to Sql 左外连接与 Group By 和 Have 子句

Posted

技术标签:

【中文标题】LINQ to Sql 左外连接与 Group By 和 Have 子句【英文标题】:LINQ to Sql Left Outer Join with Group By and Having Clause 【发布时间】:2015-02-28 02:25:40 【问题描述】:

我花了一天时间尝试将 sql 查询转换为 LINQ lambda 表达式,但没有成功。

我的sql查询:

SELECT a.ID,
       Sum(b.[Value]) AS [Value],
       c.ContractValue
FROM   Contracts a
       LEFT JOIN DepositHistories b
              ON b.ContractID = a.ID
       INNER JOIN LearningPackages c
               ON a.LearningPackageID = c.ID
GROUP  BY a.ID,
          c.ContractValue
HAVING Sum(b.[Value]) < c.ContractValue
        OR Sum(b.[Value]) IS NULL
        OR Sum(b.[Value]) = 0 

这是 LINQ 查询:

var contracts = (
                from a in db.Contracts
                from b in db.LearningPackages.Where(e => e.ID == a.LearningPackageID).DefaultIfEmpty()
                group a by new
                
                    a.ID,
                    b.ContractValue
                 into g
                from c in db.DepositHistories.Where(e => e.ContractID == g.Key.ID).DefaultIfEmpty()
                where g.Sum(e => c.Value) < g.Key.ContractValue || g.Sum(e => c.Value) == null
                select new
                
                    ID = g.Key.ID,
                    ContractValue = g.Key.ContractValue,
                    Value = g.Sum(e => c.Value != null ? c.Value : 0)
                
                ).ToList();

我的结果:

  ID  ContractValue    Value  
  1      6000000      500000  
  1      6000000      500000  
  1      6000000      500000  
  1      6000000      500000  
  1      6000000      500000  
  3      7000000      500000  
  3      7000000      500000  
  3      7000000      500000  
  4      6000000      500000  
  5      6000000      0  
  6      6000000      0 

这不是对值进行分组和求和。

请帮帮我!

谢谢!

【问题讨论】:

你一整天都在尝试什么?展示你的努力。 我们不是代码编写服务。我们帮助修复无效或不完整的代码。 您确定不希望在您的 LEFT JOIN 之前执行此 INNER JOIN 吗???? @M.Ali:连接不一定按照它们声明的顺序执行。 我只是更新我的代码,请帮助我! 【参考方案1】:

你可以这样做:

var result = from b in db.DepositHistories
             join a in db.Contracts on b.CotractID equals a.ID
             join c in db.LearningPackages on a.LearningPackageID equals c.ID
             group b by new a.ID,c.COntractValue into g
             where g.Sum(x=>x.Value) < g.Key.COntractValue 
             || g.Sum(x=>x.Value) == null 
             || g.Sum(x=>x.Value) == 0
            select new 
                   
                   ID = g.Key.ID, 
                   Value = g.Sum(x=>x.Value), 
                   ContractValue = g.Key.COntractValue
                  ;

为了更清楚,我做了一个DEMO FIDDLE。

更新:

对于左外连接,您必须执行join your condition into somealiasfrom alias in somealias.DefaultIfEmpty()

这是带有左外连接的版本,它给出了正确的结果:

var result = from a in Contracts
             join b in DepositHistories on a.ID equals b.CotractID into e
             from f in e.DefaultIfEmpty()
             join c in LearningPackages on a.LearningPackageID equals c.ID
             group f by new 
                        
                          a.ID, 
                          c.COntractValue 
                        into g
             where g.Sum(x => x==null ? 0 : x.Value) < g.Key.COntractValue 
             ||  g.Sum(x => x==null ? 0 : x.Value) == 0
             select new 
                    
                      ID = g.Key.ID, 
                      Value = g.Sum(x => x == null ? 0 : x.Value), 
                      ContractValue = g.Key.COntractValue 
                   ;

UPDATED FIDDLE DEMO

您也可以查看this SO post about How to do left outer join in LINQ

更新 2:

使用查询方法,您必须使用GroupJoin() method 进行左外连接。

这是上面带有方法查询的代码:

var Result = Contracts.GroupJoin(DepositHistories, 
                                    a => a.ID, 
                                    b => b.CotractID, 
                                    (a, b) => new  a = a, b = b )
                                  .Join(LearningPackages, 
                                  a => a.a.LearningPackageID, 
                                  b => b.ID, 
                                  (a, b) => new  a = a, b = b )
                                  .GroupBy(e => new 
                                                     
                                                        e.a.a.ID, 
                                                        e.b.COntractValue 
                                                    , 
                                                    (k, g) => new 
                                                                 
                                                                    ID = k.ID, 
                                                                    ContractValue = k.COntractValue, 
                                                                    Value =  g.Sum(x => x == null ? 0 : x.a.b.Sum(d=>d.Value)) 
                                                                
                                            ).Where(x => x.Value < x.ContractValue || x.Value == 0).ToList();

UPDATED FIDDLE WITH METHOD QUERY

【讨论】:

感谢您的代码,但此代码无法获取我所有的合约,其中 DepositHistories 为空。 我的 sql 查询已经离开了连接,我如何在 LINQ 查询中做到这一点? @SơnLê 检查更新的帖子和更新的演示,现在它会给出准确的结果,现在它是左外连接 into e from f in e.DefaultIfEmpty() 正在做左外连接 @Son Le In 方法查询我们有 groupjoin 方法请参阅我在答案中添加的链接的 SO 帖子,目前我在手机上,所以不能做太多,将从 PC 更新我的帖子

以上是关于LINQ to Sql 左外连接与 Group By 和 Have 子句的主要内容,如果未能解决你的问题,请参考以下文章

左外连接和多重计数 SQL to LINQ

LINQ to SQL 左外连接

Linq to Sql:多个左外连接

Linq To Sql 左外连接 - 过滤空结果

使用 Linq to Sql 的左外连接结果问题

LINQ to SQL 执行联合和左外连接