针对同一个Entity Framework DbSet的两个不同的LINQ查询都返回相同的结果

时间:2016-06-23 18:44:26

标签: c# entity-framework linq

假设我有:

class ContractContext : DbContext
{
    DbSet<ACTIVITY> ACTIVITYs { get; set; }
}

我有以下代码,其中startSnapshot和endSnapshot是值为1和2的整数:

var activitiesStart = contractContext.ACTIVITYs.Where(a => a.VARIANCE_SNAPSHOT_ID == startSnapshot);
var activitiesEnd = contractContext.ACTIVITYs.Where(a => a.VARIANCE_SNAPSHOT_ID == endSnapshot);

这两个查询将返回相同的结果。该结果将是执行这两个查询中的第一个查询的结果。因此,如果我强制它们都使用ToList(),

执行
var activitiesStart = contractContext.ACTIVITYs.Where(a => a.VARIANCE_SNAPSHOT_ID == startSnapshot).ToList();
var activitiesEnd = contractContext.ACTIVITYs.Where(a => a.VARIANCE_SNAPSHOT_ID == endSnapshot).ToList();

然后存储在activitiesEnd中的结果将是activitiesStart查询的结果。如果我先执行activitiesEnd查询,那么反之亦然。发生了什么事?我知道它们是相同的上下文,我想我可以看到可能如何在执行之前创建它们时如何组合查询。然而,在第二种情况下,一个在另一个被创建之前执行,那么为什么它会践踏第二个查询呢?

生成的SQL(两者都相同):

{SELECT 
    [Extent1].[ACTIVITY_ID] AS [ACTIVITY_ID], 
    [Extent1].[ACTIVITY_NAME] AS [ACTIVITY_NAME], 
    [Extent1].[WBS_ID] AS [WBS_ID], 
    [Extent1].[VARIANCE_SNAPSHOT_ID] AS [VARIANCE_SNAPSHOT_ID], 
    [Extent1].[DUE_DATE] AS [DUE_DATE], 
    [Extent1].[IS_COMPLETE] AS [IS_COMPLETE]
FROM [p6].[ACTIVITY] AS [Extent1]
WHERE [Extent1].[VARIANCE_SNAPSHOT_ID] = @p__linq__0}

实施例

var activitiesStart = contractContext.ACTIVITYs.Where(a => a.VARIANCE_SNAPSHOT_ID == 1).ToList();
var activitiesEnd = contractContext.ACTIVITYs.Where(a => a.VARIANCE_SNAPSHOT_ID == 2).ToList();

foreach (var item in activitiesStart)
{
    Debug.Write(item.VARIANCE_SNAPSHOT_ID + " ");
}

Debug.WriteLine("");

foreach (var item in activitiesEnd)
{
    Debug.Write(item.VARIANCE_SNAPSHOT_ID + " ");
}

Debug.WriteLine("");

这会输出两行,因为activitiesStart是先执行的。如果我换掉它们,我会得到两排两个。 SQL Server Profiler显示查询已正确发送到服务器。

2 个答案:

答案 0 :(得分:0)

由于延迟执行的工作方式,可能会在查询之间产生一些串扰。查询将在执行时针对参数的值运行(即,当它是ToList()或以其他方式消耗时)。

            var idA = 614;
            var idB = 130;

            var context = DbModel.ContextManager.Prism.dbo(DBName_Static);
            var custA = context.Customer.Where(x => x.Id == idA);
            var custB = context.Customer.Where(x => x.Id == idB);

            //different results (correct)
            var custA_forcedBefore = custA.ToList();
            var custB_forcedBefore = custB.ToList();

            //change the value of the input params to be the same
            idA = idB;

            //same results (incorrect). Because execution was deferred til after the parameter values were changed
            var custA_forcedAfter = custA.ToList();
            var custB_forcedAfter = custB.ToList();

编辑:我应该注意到,当我遇到这个问题时,它不是全部都在同一个函数中。在错误地假设查询已经执行之后,输入参数的值已经在堆栈中改变了。

答案 1 :(得分:0)

我无法解决这个问题。我的解决方案是在第一个执行的时候使用AsNoTracking。

var activitiesStart = contractContext.ACTIVITYs.AsNoTracking.Where(a => a.VARIANCE_SNAPSHOT_ID == startSnapshot).ToList();
var activitiesEnd = contractContext.ACTIVITYs.Where(a => a.VARIANCE_SNAPSHOT_ID == endSnapshot).ToList();