有人可以向我解释为什么我的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中。我可以验证两者的输出都是“oldpassword”。从分析SQL,我可以看到密码确实发生了变化,我还可以看到填充user2 IS 的代码进入数据库,但它只是没有使用这些值。
我理解EF将Local上下文的概念作为缓存和跟踪实体的一种方式,但据我所知,context.Installers.Where(..)
应该强制从数据库中重新提取,而context.Installers.Find()
应该看看当地的背景。似乎无论我如何查询安装程序,它都使用本地缓存。
修改
感谢@Reinard提供的解决方案。我误解了文档 - 我从here读到:
请注意,DbSet和IDbSet始终会针对数据库创建查询 并且将始终涉及到数据库的往返,即使 返回的实体已存在于上下文中。
所以我假设因为它会进入数据库,它会重新获取我的对象。实际发生的是,它进入数据库,获取对象,发现我已经在跟踪该对象(因为之前的加载),所以我最终得到了旧对象 - 这实际上是文档说的!
使用context.Installers.Local.Clear()
令人惊讶,我需要AsNoTracking().
答案 0 :(得分:5)
Where
或Find
都不会从数据库中明确重新提取。据我所知,只有在上下文中不存在实体时,Find才会从数据库中检索实体。
为了明确强制重新获取使用AsNoTracking()。
e.g。
context.Installers.AsNoTracking().Where(u => u.UserName == "admin").FirstOrDefault();