gpt4 book ai didi

linq - Linq `Where` 子句查询结果是否可以根据查询是延迟执行还是非延迟执行而有所不同?

转载 作者:行者123 更新时间:2023-12-04 02:29:22 25 4
gpt4 key购买 nike

下面是我的代码的简化版本。我希望 p1p2是平等的,还有p1_afterp2_after是相等的,因为 GetPerson1() 之间的唯一区别是和 GetPerson2().ToList()子句强制执行查询,而不更改选择标准。

我的假设不正确吗?我在我的程序中发现了一个错误,归结为 p1_afterp2_after不同(p2_after 由于年龄已更改为 26 岁,如预期的那样为 null。但 p1_after 仍然包含与 p1 相同的实例)。

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

    public void OnGet()
{
Person p1 = GetPerson1();
Person p2 = GetPerson2();

p1.Age = 26;
p2.Age = 26;

Person p1_after = GetPerson1(); // not null, but p1_after.Age is 26
Person p2_after = GetPerson2(); // null
}

public Person GetPerson1()
{
return _context
.Persons
.Where(p => p.Age == 25)
.SingleOrDefault();
}

public Person GetPerson2()
{
return _context
.Persons
.ToList()
.Where(p => p.Age == 25)
.SingleOrDefault();
}

最佳答案

这是一个疯狂的猜测,但我有一个假设,为什么你的程序会这样。

在您更改年龄后,您没有调用任何 SaveChanges/SaveChangesAsync方法,因此您的更改不会反射(reflect)在数据库中,而只会反射(reflect)在您的代码中。

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

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

  • 在两次调用之间保存对数据库的更改:
    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 将是相同的(均为空),因为现在您的更改也反射(reflect)到了数据库中。
  • 为每个调用使用一个新的上下文:
    public void OnGet()
    {
    Person p1 = GetPerson1();
    Person p2 = GetPerson2();

    p1.Age = 26;
    p2.Age = 26;

    Person p1_after = GetPerson1();
    Person p2_after = GetPerson2();
    }

    public Person GetPerson1()
    {
    using(var context = new ...)
    {
    return context
    .Persons
    .Where(p => p.Age == 25)
    .SingleOrDefault();
    }
    }

    public Person GetPerson2()
    {
    using(var context = new ...)
    {
    return context
    .Persons
    .ToList()
    .Where(p => p.Age == 25)
    .SingleOrDefault();
    }
    }

    在这种情况下,我猜 p1_after 和 p2_after 将是相同的(与之前的 p1 和 p2 一样),因为现在您的更改不会反射(reflect)到数据库中,并且没有任何缓存可行性,因为您每次调用都使用新的上下文。
  • 使用 AsNoTracking:
    public void OnGet()
    {
    Person p1 = GetPerson1();
    Person p2 = GetPerson2();

    p1.Age = 26;
    p2.Age = 26;

    Person p1_after = GetPerson1();
    Person p2_after = GetPerson2();
    }

    public Person GetPerson1()
    {
    return _context
    .Persons
    .AsNoTracking()
    .Where(p => p.Age == 25)
    .SingleOrDefault();
    }

    public Person GetPerson2()
    {
    return _context
    .Persons
    .ToList()
    .AsNoTracking()
    .Where(p => p.Age == 25)
    .SingleOrDefault();
    }

    在这种情况下,我猜 p1_after 和 p2_after 将是相同的(就像之前的 p1 和 p2 一样),因为现在 EF 跟踪被禁用 - AKA 没有缓存。
  • 关于linq - Linq `Where` 子句查询结果是否可以根据查询是延迟执行还是非延迟执行而有所不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47593855/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com