Sql 通过具有多个嵌套表进行分组并计为LINQ查询

Sql 通过具有多个嵌套表进行分组并计为LINQ查询,sql,vb.net,linq,linq-to-entities,entity-framework-4.1,Sql,Vb.net,Linq,Linq To Entities,Entity Framework 4.1,我使用以下SQL查询返回没有订单行且未分配零件的所有客户-即,我只希望每个订单的每个订单行都未分配零件的客户-(在实际问题中,我处理的是不同的域,但已转换为客户/订单以说明问题) 我在LINQ中提出的最佳方案如下: Dim qry = (From c In context.Customers Select New With { c.Customer_PK, .CountParts = (From o I

我使用以下SQL查询返回没有订单行且未分配零件的所有客户-即,我只希望每个订单的每个订单行都未分配零件的客户-(在实际问题中,我处理的是不同的域,但已转换为客户/订单以说明问题)

我在LINQ中提出的最佳方案如下:

Dim qry =     
(From c In context.Customers
 Select New With { c.Customer_PK,
                  .CountParts = 
                      (From o In c.Orders
           From l In o.OrderLines
                       Select l.Parts.Count).DefaultIfEmpty.Sum})

qry = (From grp In qry
       Where grp.CountParts  = 0
       Select grp.Customer_PK)
这是可行的,但生成的SQL不是最理想的—它对客户查询的每一行进行子查询,而不是使用GROUPBY和Having。我尝试通过语法使LINQ组工作,但它一直将过滤器作为WHERE not HAVING子句

有什么想法吗

编辑以下答案:

我接受JamieSee的回答,因为它解决了所述的问题,即使它没有通过我最初的查询生成组

谢谢Peter和Nick在这方面的意见。我是一名VB开发人员,因此在将您的代码转换为VB时遇到了一个难题,这是我最接近的一次,但它并没有产生所需的输出:

Dim qry = From c In context.Customers
          Group Join o In context.Orders On c.Customer_PK Equals o.Customer_FK
          Into joinedOrders = Group
          From jo In joinedOrders.DefaultIfEmpty
          Group Join l In context.OrderLines On jo.Order_PK Equals l.Order_FK
          Into joinedLines = Group
          From jl In joinedLines.DefaultIfEmpty
          Group c By Key = New With {c.Customer_PK, jl} Into grp = Group
          Where Key.jl Is Nothing OrElse Not Key.jl.Parts.Any
          Select c.Customer_PK 
我遇到的问题是,我必须按“Key”将“jl”推入Group,以便从Where子句引用它,否则编译器无法看到该变量或出现在Group By子句之前的任何其他变量


使用指定的过滤器,我可以获得至少一个订单中有行没有零件的所有客户,而不是任何订单中只有没有零件的客户。

只是一个提示。如果没有生成的模型,很难创建查询(C#):


像这样的东西怎么样:

var qry = from c in db.Customers
            join o in db.Orders.Where(x => x.Customer_FK == c.Customer_PK)
            join l in db.OrderLines.Where(x => x.Order_FK = o.Order_PK).DefaultIfEmpty()
            join p in db.Parts.Where(x => x.OrderLine_FK = l.OrderLine_PK).DefaultIfEmpty()
            group c by new
            {
                c.Customer_PK
            } into g
            where g.Count(p => p.Part_PK != null) == 0
            select new
            {
                Customer_PK = g.Key.Customer_PK
            };

假定你不关心计数,只考虑最终的客户,考虑问题的FLLLUE重述:

识别没有任何订单的所有客户,这些订单都有零件线

这将产生:

var customersWithoutParts = from c in Context.Customers
                            where !(from o in Context.Orders
                                    from l in o.Lines
                                    from p in l.Parts
                                    select o.Customer_FK).Contains(c.Customer_PK)
                            select c.Customer_PK;
这将产生大致相当于以下内容的已发出SQL:

SELECT     c.Customer_PK
FROM         Customers AS c
WHERE     (NOT EXISTS
                          (SELECT     o.Cusomer_FK
                            FROM          Orders AS o INNER JOIN
                                                   OrderLines AS l ON o.Order_PK = l.Order_FK INNER JOIN
                                                   Parts AS p ON l.OrderLine_PK = p.OrderLine_FK
                            WHERE      (o.Customer_FK = c.Customer_PK))) 
var customersWithoutParts = from c in Context.Customers
                            from o in c.Orders.DefaultIfEmpty()
                            from l in o.Lines.DefaultIfEmpty()
                            join part in Context.Parts on part.OrderLine_FK equals l.OrderLine_PK into joinedParts
                            where joinedParts.Count() == 0
                            select c.Customer_PK;
要获取您试图复制的SQL,我首先尝试以下操作:

SELECT     c.Customer_PK
FROM         Customers AS c
WHERE     (NOT EXISTS
                          (SELECT     o.Cusomer_FK
                            FROM          Orders AS o INNER JOIN
                                                   OrderLines AS l ON o.Order_PK = l.Order_FK INNER JOIN
                                                   Parts AS p ON l.OrderLine_PK = p.OrderLine_FK
                            WHERE      (o.Customer_FK = c.Customer_PK))) 
var customersWithoutParts = from c in Context.Customers
                            from o in c.Orders.DefaultIfEmpty()
                            from l in o.Lines.DefaultIfEmpty()
                            join part in Context.Parts on part.OrderLine_FK equals l.OrderLine_PK into joinedParts
                            where joinedParts.Count() == 0
                            select c.Customer_PK;

请注意,在VB中,这里的
连接将被
组连接所取代

谢谢,我将接受这个答案,因为它适用于我给出的示例并给出了合理的SQL。如果不是没有零件,而是我要求了一个特定的数字,那么我相信这个答案不再有效,因为不存在必然意味着COUNT=0。更广泛的问题仍然是,如何说服LINQ to Entities生成SQL GROUP,并使用类似于示例的语法。更新了答案,我认为应该生成原始SQL。我还没有测试更新的部分。让我知道这对你有什么好处。