1

有人可以向我解释为什么我下面的 EF(4.3)代码第一个代码会导致检索到“旧”密码。

using (var context = new CableSenseInstanceConfiguratorContext())
{
    var user = context.Installers.Where(u => u.UserName == "admin").FirstOrDefault();
    Console.WriteLine(user.Password); // Outputs "oldpassword"

    // Change the details on a different context;
    using (var context2 = new CableSenseInstanceConfiguratorContext())
    {
        var installer = context2.Installers.Single(i => i.UserName == "admin");
        installer.Password = "changed"; 
        context2.SaveChanges();
    }

    var user2 = context.Installers.Where(u => u.UserName == "admin").FirstOrDefault();
    Console.WriteLine(user2.Password); // Outputs "oldpassword"
}

密码是“oldpassword”启动。所以我在另一个上下文(context2)中更改密码,然后再次将其提取到 user2 中。我可以验证两者的输出都是“旧密码”。通过分析 SQL,我可以看到密码确实被更改了,我还可以看到填充 user2 的代码正在进入数据库,但它只是没有使用这些值。

我了解 EF 将本地上下文的概念作为缓存和跟踪实体的一种方式,但据我了解,acontext.Installers.Where(..)应该强制从数据库中重新获取,而 acontext.Installers.Find()应该查看本地上下文。似乎无论我如何查询安装程序,它都在使用本地缓存。

编辑

感谢@Reinard 的解决方案。我误解了文档 - 我从这里读到:

请注意,DbSet 和 IDbSet 始终会针对数据库创建查询,并且始终会涉及到数据库的往返行程,即使返回的实体已经存在于上下文中。

所以我假设因为它会进入数据库,它会重新获取我的对象。实际发生的事情是它进入数据库,获取对象,发现我已经在跟踪该对象(因为之前的负载),所以我最终得到了旧对象 - 这实际上是文档所说的!

令人惊讶的是,使用context.Installers.Local.Clear()没有区别,我需要AsNoTracking().

4

1 回答 1

5

既不WhereFind不会显式地从数据库中重新获取。据我所知,只有当上下文中不存在实体时,Find 才会从数据库中检索实体。

为了显式强制重新获取,请使用 AsNoTracking()。

例如

context.Installers.AsNoTracking().Where(u => u.UserName == "admin").FirstOrDefault();
于 2012-07-09T10:41:23.593 回答