我注意到我的Entity Framework查询生成了一些非常难看的SQL。当我检查SQL时,即使是非常简单的查询也会产生大量额外的JOIN。
我创建了一个简单的模型:
OrderID INT PK
OrderDate DATETIME
OrderID INT PK / FK
StatusID INT FK
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#端看是很麻烦的。
有人知道如何解决这个问题吗?
答案 0 :(得分:4)
实体框架生成的SQL在许多情况下都可以,但肯定会出现这样的情况:您会对生成的SQL不满意。
首先,你真的在乎吗?它是否会导致性能问题(可能不会),或者您是否有背后的DBA,如果您将其投入生产,它会射击你? : - )
如果你能忍受它,不要打扰。否则,是的,您将必须监视为查询生成的SQL,并调整您的linq查询,或采用存储过程或其他数据访问方式(或者可能切换ORM ...)。
编辑:这个特殊情况显然仍然是EF 4中的一个错误......答案 1 :(得分:1)
答案 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版本中解决。