【问题标题】:LINQ - Left Join, Group By, and CountLINQ - 左连接、分组依据和计数
【发布时间】:2010-10-16 06:44:48
【问题描述】:

假设我有这个 SQL:

SELECT p.ParentId, COUNT(c.ChildId)
FROM ParentTable p
  LEFT OUTER JOIN ChildTable c ON p.ParentId = c.ChildParentId
GROUP BY p.ParentId

如何将其转换为 LINQ to SQL?我卡在了 COUNT(c.ChildId),生成的 SQL 似乎总是输出 COUNT(*)。到目前为止,这是我得到的:

from p in context.ParentTable
join c in context.ChildTable on p.ParentId equals c.ChildParentId into j1
from j2 in j1.DefaultIfEmpty()
group j2 by p.ParentId into grouped
select new { ParentId = grouped.Key, Count = grouped.Count() }

谢谢!

【问题讨论】:

    标签: c# .net linq linq-to-sql


    【解决方案1】:
    from p in context.ParentTable
    join c in context.ChildTable on p.ParentId equals c.ChildParentId into j1
    from j2 in j1.DefaultIfEmpty()
    group j2 by p.ParentId into grouped
    select new { ParentId = grouped.Key, Count = grouped.Count(t=>t.ChildId != null) }
    

    【讨论】:

    • 好吧,这行得通,但为什么呢?你是怎么想的?不计算空值如何给我们与 COUNT(c.ChildId) 相同的结果?谢谢。
    • 这就是 SQL 的工作方式。 COUNT(fieldname) 将计算该字段中不为空的行。也许我不明白你的问题,如果是这样,请澄清一下。
    • 我想我一直在考虑计算行数,但你是对的,只计算非空值。谢谢。
    • .Count() 将生成 COUNT(*) ,顺便说一下,它将计算该组中的所有行。
    • 我遇到了完全相同的问题,但是比较 t=>t.ChildID != null 对我不起作用。结果总是一个空对象,Resharper 抱怨这个表达式总是正确的。所以我使用了 (t => t != null),这对我有用。
    【解决方案2】:

    考虑使用子查询:

    from p in context.ParentTable 
    let cCount =
    (
      from c in context.ChildTable
      where p.ParentId == c.ChildParentId
      select c
    ).Count()
    select new { ParentId = p.Key, Count = cCount } ;
    

    如果查询类型通过关联连接,则简化为:

    from p in context.ParentTable 
    let cCount = p.Children.Count()
    select new { ParentId = p.Key, Count = cCount } ;
    

    【讨论】:

    • 如果我没记错的话(已经有一段时间了),那个查询是一个大查询的简化版本。如果我需要的只是钥匙和计数,那么您的解决方案会更干净/更好。
    • 您的评论在原始问题和赞成答案的上下文中没有意义。此外 - 如果您想要的不仅仅是键,您还可以从中提取整个父行。
    • 带有let 关键字的解决方案将生成与@Mosh 组加入解决方案相同的子查询。
    • @MohsenAfshin 是的,它会生成一个子查询,与我在其正上方的答案中带有子查询的查询相同。
    【解决方案3】:

    迟到的答案:

    如果您所做的只是 Count(),那么您根本不需要左连接。请注意,join...into 实际上被转换为GroupJoin,它返回像new{parent,IEnumerable<child>} 这样的分组,所以你只需要在组上调用Count()

    from p in context.ParentTable
    join c in context.ChildTable on p.ParentId equals c.ChildParentId into g
    select new { ParentId = p.Id, Count = g.Count() }
    

    在扩展方法语法中,join into 等效于 GroupJoin(而没有 intojoinJoin):

    context.ParentTable
        .GroupJoin(
                       inner: context.ChildTable
            outerKeySelector: parent => parent.ParentId,
            innerKeySelector: child => child.ParentId,
              resultSelector: (parent, children) => new { parent.Id, Count = children.Count() }
        );
    

    【讨论】:

      【解决方案4】:

      虽然 LINQ 语法背后的想法是模拟 SQL 语法,但您不应总是考虑将 SQL 代码直接转换为 LINQ。在这种特殊情况下,我们不需要执行 group into,因为 join into 本身就是一个组加入。

      这是我的解决方案:

      from p in context.ParentTable
      join c in context.ChildTable on p.ParentId equals c.ChildParentId into joined
      select new { ParentId = p.ParentId, Count = joined.Count() }
      

      与这里投票最多的解决方案不同,我们不需要在 Count(t => t.ChildId != null 中检查 j1j2 和 null )

      【讨论】:

        【解决方案5】:
         (from p in context.ParentTable     
          join c in context.ChildTable 
            on p.ParentId equals c.ChildParentId into j1 
          from j2 in j1.DefaultIfEmpty() 
             select new { 
                  ParentId = p.ParentId,
                 ChildId = j2==null? 0 : 1 
              })
           .GroupBy(o=>o.ParentId) 
           .Select(o=>new { ParentId = o.key, Count = o.Sum(p=>p.ChildId) })
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-05-05
          • 2017-04-10
          • 2017-11-21
          • 2014-11-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多