linq - Entity Framework 似乎不必要地两次加入同一个表

标签 linq entity-framework

更新 这可能已经修复:http://entityframework.codeplex.com/workitem/486

...

针对我的实体的相当简单的 LINQ 语句导致了不必要的复杂 SQL。稍后会详细介绍,这是设置:



出版物

  • 出版物 ID (pk)
  • TopicId(转到主题表)
  • ReceiptCount(非规范化查询性能)
  • 插入日期

  • 收据
  • ReceiptId (pk)
  • PublicationId(翻到上表)
  • 插入日期

  • LINQ
    var query = from r in context.Receipts.Include("Publication")
                where r.DateInserted < lagDate
                && r.ReceiptId > request.AfterReceiptId
                && r.Publication.TopicId == topicEntity.TopicId
                && r.Publication.ReceiptCount > 1
                select r;
    

    SQL
    exec sp_executesql N'SELECT TOP (25) 
    [Project1].[ReceiptId] AS [ReceiptId], 
    [Project1].[PublicationId] AS [PublicationId], 
    [Project1].[DateInserted] AS [DateInserted], 
    [Project1].[DateReceived] AS [DateReceived], 
    [Project1].[PublicationId1] AS [PublicationId1], 
    [Project1].[PayloadId] AS [PayloadId], 
    [Project1].[TopicId] AS [TopicId], 
    [Project1].[BrokerType] AS [BrokerType], 
    [Project1].[DateInserted1] AS [DateInserted1], 
    [Project1].[DateProcessed] AS [DateProcessed], 
    [Project1].[DateUpdated] AS [DateUpdated], 
    [Project1].[PublicationGuid] AS [PublicationGuid], 
    [Project1].[ReceiptCount] AS [ReceiptCount]
    FROM ( SELECT 
        [Extent1].[ReceiptId] AS [ReceiptId], 
        [Extent1].[PublicationId] AS [PublicationId], 
        [Extent1].[DateInserted] AS [DateInserted], 
        [Extent1].[DateReceived] AS [DateReceived], 
        [Extent3].[PublicationId] AS [PublicationId1], 
        [Extent3].[PayloadId] AS [PayloadId], 
        [Extent3].[TopicId] AS [TopicId], 
        [Extent3].[BrokerType] AS [BrokerType], 
        [Extent3].[DateInserted] AS [DateInserted1], 
        [Extent3].[DateProcessed] AS [DateProcessed], 
        [Extent3].[DateUpdated] AS [DateUpdated], 
        [Extent3].[PublicationGuid] AS [PublicationGuid], 
        [Extent3].[ReceiptCount] AS [ReceiptCount]
        FROM   [dbo].[Receipt] AS [Extent1]
        INNER JOIN [dbo].[Publication] AS [Extent2] ON [Extent1].[PublicationId] = [Extent2].[PublicationId]
        LEFT OUTER JOIN [dbo].[Publication] AS [Extent3] ON [Extent1].[PublicationId] = [Extent3].[PublicationId]
        WHERE ([Extent2].[ReceiptCount] > 1) AND ([Extent1].[DateInserted] < @p__linq__0) AND ([Extent1].[ReceiptId] > @p__linq__1) AND ([Extent2].[TopicId] = @p__linq__2)
    )  AS [Project1]
    ORDER BY [Project1].[ReceiptId] ASC',N'@p__linq__0 datetime,@p__linq__1 int,@p__linq__2 int',@p__linq__0='2012-09-05 19:39:21:510',@p__linq__1=4458824,@p__linq__2=90
    

    问题

    出版物被加入两次:
  • LEFT OUTER JOIN 因为 .Include("Publication")
  • INNER JOIN 因为 where .

  • 如果我从 SQL 中完全删除 [Extent2],并将 WHERE 位更改为使用 [Extent3],则会得到相同的结果。由于我没有在实体上使用延迟加载,因此我必须 .Include("Publication") ……有什么解决办法吗?

    我正在使用 EF4,但从 NuGet 中获取了 EF5 以查看它是否已修复,但它产生了相同的结果(尽管我不知道如何判断我的 EDMX 是否真的在使用 EF5)。

    最佳答案

    但是,有一个解决方法。它可能不是最优雅的解决方案,但它完全符合您的要求;它只生成一个连接。

    改变:

    var query = from r in context.Receipts.Include("Publication")    
                where r.DateInserted < lagDate 
                && r.ReceiptId > request.AfterReceiptId 
                && r.Publication.TopicId == topicEntity.TopicId 
                && r.Publication.ReceiptCount > 1 
                select r; 
    

    成为:
    var query = from r in context.Receipts
                join pub in context.Publication on r.PublicationId equals pub.PublicationId
                where r.DateInserted < lagDate 
                && r.ReceiptId > request.AfterReceiptId 
                && pub.TopicId == topicEntity.TopicId 
                && pub.ReceiptCount > 1 
                select new {
                    Receipt = r,
                    Publication = pub
                }; 
    

    请注意,我们已经删除了 Include 并且我们不再使用 r.Publication。??在 where 子句中。相反,我们正在使用 pub.??

    现在,当您循环查询时,您将看到 r.Publication 不为空:
    foreach ( var item in query)
    {
        //see that item.Publication is not null
        if(item.Receipt != null && item.Receipt.Publication != null)
        {
            //do work based on a valid Publication
        }
        else
        {
            //do work based on no linked Publication
        }
    }
    

    关于linq - Entity Framework 似乎不必要地两次加入同一个表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12289070/

    相关文章:

    c# - 从 lambda 表达式中的函数调用获取返回值

    c# - 按相等缓存 LINQ 表达式

    linq - 从 List-LINQ 中删除重复项

    c# - 在 ASP.NET MVC 中不使用 IoC/DI、UoW 和存储库模式将逻辑从 Controller 操作移动到 "service layer"

    javascript - 将数据列表获取为 HTML,从 JavaScript 中的 Controller 中选择

    c# - Entity Framework DbSet 反射

    entity-framework - 架构无效且类型无法加载,因为程序集包含 EdmSchemaAttribute

    c# - LINQ:一起使用 AssociateWith 和 Distinct

    entity-framework - Entity Framework MigrateDatabaseToLatestVersion 给出错误

    linq - MongoDb c# Linq 查询并返回集合的子对象