EF 4.3使用本地缓存而不是从数据库重新获取

问题描述:

有人可以向我解释为什么我的EF(4.3)代码首先下面的代码导致“旧”密码被检索。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,我可以看到密码确实发生了变化,我还可以看到填充到数据库的代码,但它只是不使用这些值。

据我所知,英孚已经在本地上下文缓存和跟踪实体的方法的概念,但是从我的理解,一个context.Installers.Where(..)应该强制从数据库中重新读取,而context.Installers.Find()应该看看当地的情况。看来,无论我如何查询安装程序,它都使用本地缓存。

EDIT

由于@Reinard的溶液。我被误解的文档 - 我从here阅读:

注意DbSet和IDbSet始终对数据库 创建查询和总会涉及往返于即使 实体已经返回数据库中存在的背景下, 。

所以我认为,因为它会去数据库,它会重新获取我的对象。究竟发生了什么,它到了数据库,取得了对象,发现我已经在跟踪那个对象(因为之前的负载),所以我最终得到了旧对象 - 这实际上是文档说的!

使用context.Installers.Local.Clear()没什么区别奇怪的是,我需要AsNoTracking().

+1

你确定你正在比较相同的记录吗?在第一个上下文中,您正在使用.Where(...)。FirstOrDefault()和第二个上下文中使用.Single(...)。生成的SQL是否相同? – Maarten 2012-07-09 10:29:35

+0

我不能重现描述的行为,并同意whit @Maarten – tschmit007 2012-07-09 10:37:13

+0

绝对100%肯定 - 唯一不同的Linq表达式与我用来更新DB中的记录的第二个上下文,所以它并不重要这个Linq很不同。分析器验证正确的记录得到更新 – 2012-07-09 11:57:57

无论WhereFind将明确地从数据库中重新提取。据我所知Find只有在上下文中不存在的情况下才会从数据库中检索实体。

为了明确强制使用AsNoTracking()重新读取。

例如

context.Installers.AsNoTracking().Where(u => u.UserName == "admin").FirstOrDefault(); 
+0

辉煌 - 我明白现在发生了什么:)我是错误的文件,谢谢你 - 我会编辑我的问题来详细说明 – 2012-07-09 12:02:19

+0

非常好,我只是寻找这非常同样的答案,因为我需要获取原始的完整obj图,因为它在数据库中并将其与其他修改的实例进行比较 – 2013-07-22 00:35:42