Linq`哪里'子句查询结果可以根据查询是懒惰还是非懒惰执行而不同?

时间:2017-12-01 12:53:47

标签: linq entity-framework-core

以下是我的代码的简化版本。我希望p1p2相等,同时p1_afterp2_after相等,因为GetPerson1()和{{1}之间的唯一区别是GetPerson2()子句强制执行查询,而不对选择条件进行任何更改。

我的假设不正确吗?我在程序中发现了一个错误,归结为.ToList()p1_after不同(p2_after因预期年龄已更改为26而为空。但是{{1}仍然包含与p2_after)相同的实例。

这种行为是正常的吗?这对我来说似乎不合逻辑,这就是我想检查的原因。特别是p1_after返回26,尽管已选择p1使其p1_after.Age为25。

p1_after

1 个答案:

答案 0 :(得分:2)

这是一个疯狂的猜测,但我假设你的程序行为如此。

更改年龄后,您没有调用任何window.onload / SaveChanges方法,因此您的更改未反映在数据库中,只反映在您的代码中。

现在,当您再次调用SaveChangesAsync方法时,您要求从数据库中获取年龄为25岁的人,并且由于您的更改未反映数据库,因此您获得的结果与以前相同。 /> 奇怪的部分是你在调用GetPerson1方法时获得不同结果的原因,这将是我的猜测 - 在GetPerson2方法中你执行GetPerson2将所有人带入记忆中然后你在内存中过滤结果,而不是ToList方法,当过滤发生在数据库级别时,我的猜测是当你第二次调用GetPersons1方法时,因为你使用相同的上下文{{1使用一些缓存机制来检索所有使您正在过滤的列表受到更改影响的人,并且在此列表中没有任何年龄为25的人,这就是p2_after为空的原因。

为了确认或拒绝我的假设,我将尝试三种不同的方案:

  • 在两次调用之间保存对数据库的更改:

    GetPerson2

    在这种情况下,我猜p1_after和p2_after将是相同的(都为null),因为现在您的更改也会反映到数据库中。

  • 为每次通话使用新的上下文:

    EntityFramework

    在这种情况下,我猜p1_after和p2_after将是相同的(p1和p2都在之前),因为现在你的更改没有反映到数据库中,并且没有任何缓存可行性,因为你每次调用都使用了新的上下文

  • 使用AsNoTracking:

    public void OnGet()
    {
        Person p1 = GetPerson1();
        Person p2 = GetPerson2();
    
        p1.Age = 26;
        p2.Age = 26;
    
        _context.SaveChanges();
    
        Person p1_after = GetPerson1();
        Person p2_after = GetPerson2();
    }
    

    在这种情况下,我猜p1_after和p2_after将是相同的(p1和p2都在之前),因为现在EF跟踪被禁用 - AKA没有缓存。