【问题标题】:Entity Framework - Navigation Properties Generating Extra JOINs实体框架 - 生成额外连接的导航属性
【发布时间】:2011-02-21 21:51:48
【问题描述】:

我注意到我的实体框架查询生成了一些非常丑陋的 SQL。当我检查 SQL 时,即使是非常简单的查询也会产生大量额外的 JOIN。

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

订单

OrderID INT PK
订单日期日期时间

OrderHeaders

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# 方面看会更难看。

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

【问题讨论】:

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


    【解决方案1】:

    Entity Framework 生成的 SQL 在很多情况下是可以的,但肯定会有你对生成的 SQL 皱眉的情况。

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

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

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

    【讨论】:

    • 我想这就是我的问题真正归结为的原因。 SQL 优化器是否足够聪明,不会在意您加入 3 次?如果一个更复杂的查询在同一个连接中放置 10 次呢?
    【解决方案2】:

    是的。我注意到了同样的事情。希望多余的加入不会严重影响您的表现。希望 EF5 能解决这个问题。

    见:

    Too Many Left Outer Joins in Entity Framework 4?

    【讨论】:

      【解决方案3】:

      对我来说,它看起来像一个错误。如果你只是运行:

        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 版本中解决。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-29
        相关资源
        最近更新 更多