实体框架 - 导航属性生成额外的JOIN

时间:2011-02-21 21:51:49

标签: c# .net entity-framework-4 linq-to-entities

我注意到我的Entity Framework查询生成了一些非常难看的SQL。当我检查SQL时,即使是非常简单的查询也会产生大量额外的JOIN。

我创建了一个简单的模型:

订单

OrderID INT PK
OrderDate DATETIME

OrderHeaders

OrderID INT PK / FK
StatusID INT FK

StatusTypes

StatusID INT PK
说明NVARCHAR(50)

从模型中,订单可以包含0或1个订单标题。标题将具有1种状态类型。

我创建了以下查询:

var orders = from o in db.Orders
             where o.OrderID == 1
             select new
             {
                 Order = o,
                 Status = o.OrderHeader.Status
             };

由此生成的SQL看起来像:

SELECT 
    [Extent1].[OrderID] AS [OrderID], 
    [Extent1].[OrderDate] AS [OrderDate], 
    [Extent4].[StatusID] AS [StatusID], 
    [Extent4].[Description] AS [Description]
FROM    [dbo].[Orders] AS [Extent1]
LEFT OUTER JOIN [dbo].[OrderHeaders] AS [Extent2] ON [Extent1].[OrderID] = [Extent2].[OrderID]
LEFT OUTER JOIN [dbo].[OrderHeaders] AS [Extent3] ON [Extent2].[OrderID] = [Extent3].[OrderID]
LEFT OUTER JOIN [dbo].[StatusTypes] AS [Extent4] ON [Extent3].[OrderID] = [Extent4].[OrderID]
WHERE 1 = [Extent1].[OrderID]

如您所见,查询中有两个不必要的左连接。为什么SQL会像这样生成?我在质疑这个错误吗?我不应该在查询中使用导航属性吗?

我是否需要在查询本身中编写联接,以便它不会为我生成额外的连接?当我使用连接编写查询时,生成的SQL没有任何额外的JOIN,但LINQ to Entities查询更加丑陋/更详细:

var orders = from o in db.Orders
             join h in db.OrderHeaders on o.OrderID equals h.OrderID into orderHeader
             from h in orderHeader.DefaultIfEmpty()
             join s in db.StatusTypes on h.StatusID equals s.StatusID into statusType
             from s in statusType.DefaultIfEmpty()
             where o.OrderID == 1
             select new
             {
                 o,
                 s
             };

这会在没有额外连接的情况下生成SQL,但从C#端看是很麻烦的。

有人知道如何解决这个问题吗?

3 个答案:

答案 0 :(得分:4)

实体框架生成的SQL在许多情况下都可以,但肯定会出现这样的情况:您会对生成的SQL不满意。

首先,你真的在​​乎吗?它是否会导致性能问题(可能不会),或者您是否有背后的DBA,如果您将其投入生产,它会射击你? : - )

如果你能忍受它,不要打扰。否则,是的,您将必须监视为查询生成的SQL,并调整您的linq查询,或采用存储过程或其他数据访问方式(或者可能切换ORM ...)。

编辑:这个特殊情况显然仍然是EF 4中的一个错误......

答案 1 :(得分:1)

是的。我注意到了同样的事情。希望多余的加入不会让你的表现太糟糕。希望EF5能够清理它。

请参阅:

Too Many Left Outer Joins in Entity Framework 4?

答案 2 :(得分:0)

对我而言,它看起来像一个bug。如果您只是运行:

  var orders = from o in context.Orders
               where o.OrderId == 1
               select o.OrderHeader;

它会产生这个:

SELECT 
[Extent1].[OrderId] AS [OrderId], 
[Extent3].[OrderId] AS [OrderId1], 
[Extent3].[Name] AS [Name], -- I added  this column to OrderHeaders
[Extent4].[StatusId] AS [StatusId]
FROM    [dbo].[Orders] AS [Extent1]
LEFT OUTER JOIN [dbo].[OrderHeaders] AS [Extent2] ON [Extent1].[OrderId] = [Extent2].[OrderId]
LEFT OUTER JOIN [dbo].[OrderHeaders] AS [Extent3] ON [Extent2].[OrderId] = [Extent3].[OrderId]
LEFT OUTER JOIN [dbo].[OrderHeaders] AS [Extent4] ON [Extent2].[OrderId] = [Extent4].[OrderId]
WHERE 1 = [Extent1].[OrderId]

修改

我想知道对此行为的一些解释,因此我将其转发到MSDN论坛。我希望,我们会得到一些答案。

编辑2:

检查this answer。确认错误将在下一个EF版本中解决。