我创建了一个实体框架模型,其中包含Northwind数据库中的两个表来测试它的一些功能:产品和CAtegories。
它自动在Category和Product之间创建了一个关联,它是0..1到*。
我写了这个简单的查询:
var beverages = from p in db.Products.Include("Category")
where p.Category.CategoryName == "Beverages"
select p;
var beverageList = beverages.ToList();
我运行SQL事件探查器并运行代码,以便我可以看到它生成的SQL,这就是它生成的内容:
SELECT
[Extent1].[ProductID] AS [ProductID],
[Extent1].[ProductName] AS [ProductName],
[Extent1].[SupplierID] AS [SupplierID],
[Extent1].[QuantityPerUnit] AS [QuantityPerUnit],
[Extent1].[UnitPrice] AS [UnitPrice],
[Extent1].[UnitsInStock] AS [UnitsInStock],
[Extent1].[UnitsOnOrder] AS [UnitsOnOrder],
[Extent1].[ReorderLevel] AS [ReorderLevel],
[Extent1].[Discontinued] AS [Discontinued],
[Extent3].[CategoryID] AS [CategoryID],
[Extent3].[CategoryName] AS [CategoryName],
[Extent3].[Description] AS [Description],
[Extent3].[Picture] AS [Picture]
FROM [dbo].[Products] AS [Extent1]
INNER JOIN [dbo].[Categories] AS [Extent2]
ON [Extent1].[CategoryID] = [Extent2].CategoryID]
LEFT OUTER JOIN [dbo].[Categories] AS [Extent3]
ON [Extent1].[CategoryID] = [Extent3].[CategoryID]
WHERE N'Beverages' = [Extent2].[CategoryName]
我很好奇为什么查询内部连接到类别然后离开连接到它。 select语句使用左连接表中的字段。有人能帮我理解这个的原因吗?如果我删除左连接并将选择列表更改为从Extent2中提取,则会得到与此查询相同的结果。在什么情况下这不是真的?
答案 0 :(得分:2)
[Extent3]
是Include(Category)
的实现,Include不应影响“主”表产品的选择结果,因此LEFT JOIN
(产品中的所有记录和右侧的一些记录)表类别)。
[Extent2]
实际上是按相关表类别过滤所有记录,名称为“饮料”,所以在这种情况下它是强限制(INNER JOIN
)
为什么两个? :)因为为每个语句解析表达式和自动生成(包括,在哪里)
答案 1 :(得分:1)
您会注意到该查询正在从类别表别名SELECT
的副本中提取Extent3
列表中的所有列,但它是检查CategoryName 对照复制别名Extent2
。
换句话说,在这种情况下,EF的查询生成没有意识到你是Include()
并通过同一个表限制查询,所以它盲目地使用两个副本。
不幸的是,除了解释发生了什么之外,我对EF的经验还不够先进,无法提出解决方案......
答案 2 :(得分:1)
djacobson和igor很好地解释了为什么会这样。我个人使用实体框架的方式,我完全避免使用Include。根据您计划对数据执行的操作,您可以执行以下操作:
var beverages = from p in db.Products
select new {p, p.Category} into pc
where pc.Category.CategoryName == "Beverages"
select pc;
return beverages.ToList().Select(pc => pc.p);
...至少在EF 4.0中,它只会产生一个内连接。实体框架足够聪明,可以使产品的Category属性填充从数据库中带回来的类别。
当然,SQL Server很可能会优化一些东西,所以这实际上不会给你带来任何好处。
答案 3 :(得分:0)
(如果查询相同,但评论字段对此限制太多,则不直接回答您的问题)
如果你忽略了.Include()
,它是不是加载它(因为在哪里)?一般来说,使用投影代替Include()
更有意义:
var beverages = from p in db.Products.Include("Category")
where p.Category.CategoryName == "Beverages"
select new { Product = p, Category = p.Category };
var beverageList = beverages.ToList();