按组生成的查询按组加入

时间:2010-07-08 19:12:23

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

我有以下组的linq声明

from c in Categories
join p in Products on c equals p.Category into ps
select new { Category = new {c.CategoryID, c.CategoryName}, Products = ps };

但是,这会生成以下左外连接查询,并返回所有类别,即使没有关联的产品。

SELECT [t0].[CategoryID], [t0].[CategoryName], [t1].[ProductID], [t1].[ProductName],     [t1].[SupplierID], [t1].[CategoryID] AS [CategoryID2], [t1].[QuantityPerUnit],   [t1].[UnitPrice], [t1].[UnitsInStock], [t1].[UnitsOnOrder], [t1].[ReorderLevel], [t1].[Discontinued], (
    SELECT COUNT(*)
    FROM [Products] AS [t2]
    WHERE [t0].[CategoryID] = [t2].[CategoryID]
    ) AS [value]
FROM [Categories] AS [t0]
LEFT OUTER JOIN [Products] AS [t1] ON [t0].[CategoryID] = [t1].[CategoryID]
ORDER BY [t0].[CategoryID], [t1].[ProductID]

我真正想要的只是返回那些具有相关产品的类别。但如果我像这样重写linq查询:

from c in Categories
join p in Products on c equals p.Category
group p by new {c.CategoryID, c.CategoryName} into ps
select new { Category = ps.Key, Products = ps };

这给了我想要的结果,但每个类别生成一个查询:

SELECT [t0].[CategoryID], [t0].[CategoryName]
FROM [Categories] AS [t0]
INNER JOIN [Products] AS [t1] ON [t0].[CategoryID] = [t1].[CategoryID]
GROUP BY [t0].[CategoryID], [t0].[CategoryName]
GO

-- Region Parameters
DECLARE @x1 Int SET @x1 = 1
DECLARE @x2 NVarChar(9) SET @x2 = 'Beverages'
-- EndRegion
SELECT [t1].[ProductID], [t1].[ProductName], [t1].[SupplierID], [t1].[CategoryID],  [t1].[QuantityPerUnit], [t1].[UnitPrice], [t1].[UnitsInStock], [t1].[UnitsOnOrder], [t1].[ReorderLevel], [t1].[Discontinued]
FROM [Categories] AS [t0]
INNER JOIN [Products] AS [t1] ON [t0].[CategoryID] = [t1].[CategoryID]
WHERE (@x1 = [t0].[CategoryID]) AND (@x2 = [t0].[CategoryName])
GO

-- Region Parameters
DECLARE @x1 Int SET @x1 = 2
DECLARE @x2 NVarChar(10) SET @x2 = 'Condiments'
-- EndRegion
SELECT [t1].[ProductID], [t1].[ProductName], [t1].[SupplierID], [t1].[CategoryID], [t1].[QuantityPerUnit], [t1].[UnitPrice], [t1].[UnitsInStock], [t1].[UnitsOnOrder], [t1].[ReorderLevel], [t1].[Discontinued]
FROM [Categories] AS [t0]
INNER JOIN [Products] AS [t1] ON [t0].[CategoryID] = [t1].[CategoryID]
WHERE (@x1 = [t0].[CategoryID]) AND (@x2 = [t0].[CategoryName])
GO

...

有没有办法做一个内部联接和分组依据,仍然只生成一个像群组一样的查询?

2 个答案:

答案 0 :(得分:3)

var queryYouWant =
  from c in Categories 
  join p in Products on c equals p.Category
  select new {Category = c, Product = p};

var result =
  from x in queryYouWant.AsEnumerable()
  group x.Product by x.Category into g
  select new { Category = g.Key, Products = g }; 

  

有没有办法做一个内部连接和分组依据,并且仍然只生成像组连接这样的单个查询?

没有。当你说GroupBy后面是组元素的非聚合访问时,这是一个重复查询,组密钥作为过滤器。

答案 1 :(得分:2)

加入的目的是什么?

您的原始查询与此相同:

from c in Categories
select new { Category = new { c.CategoryID, c.CategoryName }, c.Products }

我在某种程度上错过了一些明显的东西???

如果您只想要包含产品的类别,请执行以下操作:

from c in Categories
where c.Products.Any()
select new { Category = new { c.CategoryID, c.CategoryName }, c.Products }

或者,如果你想平息结果:

from p in Products
select new { p, p.Category.CategoryID, p.Category.CategoryName }

后者将转换为内部或外部联接 - 取决于该关系是否可以为空。您可以按如下方式强制等效内连接:

from p in Products
where p.Category != null
select new { p, p.Category.CategoryID, p.Category.CategoryName }