2016-08-18 151 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