2012-07-09 46 views
1

有人可以向我解釋爲什麼我的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

回答

5

無論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

相關問題