2016-08-18 200 views
1

它是這樣的:奇怪的行爲

MyDbContext ctx = new MyDbContext(); 

IFooRepository repo = new FooRepository(ctx); 
var items = repo.GetAvailableItem().ToList(); //this will query all item.sold = false. 

// here it returns three rows 
foreach(var item in items) { 
    item.sold = true; 
} 

repo.commit();  // this will call the SaveChanges() in DbContext 

Thread.sleep(10000) 

// Now I quickly execute a query in SQL Server Management Studio 
// UPDATE Item SET Sold = 0; 
var items02 = repo.GetAvailableItem().ToList(); // this will query all item.sold = false. 

// here items02 also contains three rows 
// HOWEVER, when I watch the value of item.sold in items02, it is all True 

這是設計的行爲?

爲什麼?是否因爲DbContext緩存實體並且即使再次運行相同的查詢也不會刷新?


UPDATE

這裏是我的回購代碼:

public IQueryable<Item> GetAvailableItem() 
{ 
    var items = from x in DbContext.Item 
         where x.Sold == 0 
         select x; 
    return items; 
} 

public virtual int Commit() 
{ 
    return DbContext.SaveChanges(); 
} 
+3

請發表您的'GetAvailableItem()'和'提交()'方法。看起來有點犯錯 –

回答

4

確定。這是發生了什麼:

  1. 創建一個新的上下文。
  2. 通過調用db從db加載項目GetAvailableItem()
  3. 上下文將加載它們,並緩存它們。
  4. 通過上下文更新項目。所以:db行被更新,並且緩存版本也被更新。
  5. 通過純sql在上下文之外更新項目(通過SSMS)。所以:db行更新。但是,由於您使用的是與以前相同的上下文,並且它有自己的版本,因此無法知道發生了什麼,因此緩存版本的項目保持原樣:未更新。

如果你想讓你的上下文知道自身以外的變化,最簡單的方法是創建一個新的上下文並再次查詢。另一種方法是通過yourContext.Entry<YourEntityType>(entityInstance).Reload();來告訴上下文顯式重新加載db中的實體。

+0

好的解釋。現在我明白它是如何工作的。艾蒂安還陳述了一件非常重要的事情。使用dbContext時的正確做法是儘可能縮短它。 – Terrence

+0

Ur wlcm。還要記住:1.從存儲庫返回'IQueryable'不是一個好習慣。 2.使用存儲庫模式並不是一個好習慣,而DbContext是存儲庫本身。 –

+0

噢,我會改變他們所有人返回IList。謝謝 – Terrence

1

我的猜測是您的DbContext未能及時更新您在數據庫中發生的更改(您表示您在Thread.sleep期間正在運行更新)。 DbContext不會拿起這些更新(數據被緩存)。

這就是爲什麼你想盡可能縮短你的上下文環境以減少併發性的原因。這是一個預期的行爲。

看到這個MSDN post