Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linq 实体框架似乎不必要地连接同一个表两次_Linq_Entity Framework - Fatal编程技术网

Linq 实体框架似乎不必要地连接同一个表两次

Linq 实体框架似乎不必要地连接同一个表两次,linq,entity-framework,Linq,Entity Framework,更新这可能已经修复: 针对我的实体的相当简单的LINQ语句会导致不必要的复杂SQL。稍后将介绍更多信息,以下是设置: 表格 出版 PublicationId(主键) TopicId(fk到主题表) ReceiptCount(针对查询性能进行非规范化) 插入日期 收据 接收方ID(pk) PublicationId(fk到上表) 插入日期 LINQ var query = from r in context.Receipts.Include("Publication")

更新这可能已经修复:

针对我的实体的相当简单的LINQ语句会导致不必要的复杂SQL。稍后将介绍更多信息,以下是设置:

表格

出版

  • PublicationId(主键)
  • TopicId(fk到主题表)
  • ReceiptCount(针对查询性能进行非规范化)
  • 插入日期
收据

  • 接收方ID(pk)
  • PublicationId(fk到上表)
  • 插入日期
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;
var query=context.Receipts.Include(“发布”)中的r
其中r.DateInsertedrequest.AfterReceiptId
&&r.Publication.TopicId==topicEntity.TopicId
&&r.Publication.ReceiptCount>1
选择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
exec sp_executesql N'选择顶部(25)
[Project1]。[ReceiptId]作为[ReceiptId],
[Project1]。[PublicationId]作为[PublicationId],
[Project1]。[DateInserted]作为[DateInserted],
[Project1][DateReceived]作为[DateReceived],
[Project1][PublicationId1]作为[PublicationId1],
[Project1]。[PayloadId]作为[PayloadId],
[Project1]。[TopicId]作为[TopicId],
[Project1]。[BrokerType]作为[BrokerType],
[Project1]。[DateInserted1]作为[DateInserted1],
[Project1]。[DateProcessed]作为[DateProcessed],
[Project1]。[DateUpdated]为[DateUpdated],
[Project1]。[PublicationGuid]作为[PublicationGuid],
[Project1][ReceiptCount]作为[ReceiptCount]
从(选择
[Extent1]。[ReceiptId]作为[ReceiptId],
[Extent1]。[PublicationId]作为[PublicationId],
[Extent1]。[DateInserted]作为[DateInserted],
[Extent1]。[DateReceived]作为[DateReceived],
[Extent3]。[PublicationId]作为[PublicationId1],
[Extent3]。[PayloadId]作为[PayloadId],
[Extent3]。[TopicId]作为[TopicId],
[Extent3]。[BrokerType]作为[BrokerType],
[Extent3]。[DateInserted]作为[DateInserted1],
[Extent3]。[DateProcessed]作为[DateProcessed],
[Extent3]。[DateUpdate]作为[DateUpdate],
[Extent3]。[PublicationGuid]作为[PublicationGuid],
[Extent3][ReceiptCount]作为[ReceiptCount]
从[dbo].[Receipt]作为[Extent1]
内部联接[dbo].[Publication]作为[Extent1].[PublicationId]=[Extent2].[PublicationId]上的[Extent2]
[Extent1].[PublicationId]=[Extent3].[PublicationId]上的[Extent3]左外部联接[dbo].[Publication]为[Extent3]
其中([Extent2].[ReceiptCount]>1)和([Extent1].[DateInserted]<@p_uulinq_u0)和([Extent1].[ReceiptId]>@p_ulinq_u1)和([Extent2].[TopicId]=@p_ulinq_u2)
)AS[Project1]
由[Project1].[ReceiptId]ASC,N'@p_uLinq_u0 datetime,@p_uLinq_u1 int,@p_uLinq_u2 int',@p_uLinq_u0='2012-09-05 19:39:21:510',@p_uLinq_u1=4458824,@p_uLinq_u2=90订购
问题

发布被加入两次:

  • 由于
    .Include(“Publication”)
  • 由于
    的where
    而导致内部联接
  • 如果我完全从SQL中删除[Extent2],并更改使用[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; 
    

    我将通过如下更改代码来优化前一个人的答案,这样就不需要连接,这样您就不必知道需要连接哪些列,也不必在连接条件更改时更改LINQ。这本应该是不必要的,但微软目前并不专注于修复其sql代码生成

        var query = from pub in context.Publications
                    from r in pub.Reciepts
                    where r.DateInserted < lagDate 
                    && r.ReceiptId > request.AfterReceiptId 
                    && pub.TopicId == topicEntity.TopicId 
                    && pub.ReceiptCount > 1 
                    select new {
                           Receipt = r,
                           Publication = pub
                    };
    
    var query=来自context.Publications中的发布
    从酒吧里的r收到
    其中r.DateInsertedrequest.AfterReceiptId
    &&pub.TopicId==topicEntity.TopicId
    &&pub.ReceiptCount>1
    选择新的{
    收据=r,
    发布=发布
    };
    
    使用临时变量(例如,
    let
    pub=r.Publication)可以避免这种行为

    var query=context.Receipts中的r
    让pub=r.Publication//使用临时变量
    其中r.DateInsertedrequest.AfterReceiptId
    &&pub.TopicId==topicEntity.TopicId
    &&pub.ReceiptCount>1
    选择新建{r,pub};
    
    我认为where和include都在进行连接,并且没有简化为左连接。您应该将此作为EF Codeplex项目的改进发布。然而,我认为这将是相当低的优先级,因为我认为SQL对于这种“甚至”的NHibernate来说是相当有效的。将其视为自动查询生成的特殊性。数据库引擎可能会对其进行优化。“不过观察得不错。@GertArnold它实际上导致了性能问题。”。SQL事件探查器报告的持续时间为700-900毫秒,如果我删除它,我会得到0-6毫秒。男孩!坏消息。看起来它还是需要改进的。@Langdon你要删除哪一个子句?我认为这将被解释为一个
    内部连接
    ,而不是
    左连接
    @edze它应该是一个内部连接
    a内部连接b作为b1左连接b作为b2
    (提示此问题的双连接)将永远不会为
    b2
    返回空行,因为所有缺少
    b
    行的
    a
    都已被第一个连接过滤掉。也就是说,同样的想法应该可以在中实现
    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
        }
    }
    
        var query = from pub in context.Publications
                    from r in pub.Reciepts
                    where r.DateInserted < lagDate 
                    && r.ReceiptId > request.AfterReceiptId 
                    && pub.TopicId == topicEntity.TopicId 
                    && pub.ReceiptCount > 1 
                    select new {
                           Receipt = r,
                           Publication = pub
                    };
    
    var query = from r in context.Receipts
                let pub = r.Publication // using a temp variable
                where r.DateInserted < lagDate
                && r.ReceiptId > request.AfterReceiptId
                && pub.TopicId == topicEntity.TopicId
                && pub.ReceiptCount > 1
                select new { r, pub };