DbContext在实体框架中的奇怪行为

时间:2016-08-18 12:50:32

标签: c# .net entity-framework dbcontext

它是这样的:

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缓存实体并且永远不会刷新,即使您再次运行相同的查询?

更新

以下是我的仓库中的代码:

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();
}

2 个答案:

答案 0 :(得分:4)

行。这就是发生的事情:

  1. 创建新上下文。
  2. 通过调用GetAvailableItem()
  3. 从db加载项目
  4. 上下文将加载它们,并缓存它们。
  5. 通过上下文更新项目。因此:更新了db行,并且还更新了缓存版本。
  6. 通过纯sql在上下文之外(通过SSMS)更新项目。所以:db行更新了。但是,由于您使用的是与之前相同的上下文,并且它拥有自己的项目版本,并且没有办法让它知道自身外部发生了什么,因此项目的缓存版本保持不变:未更新
  7. 如果您希望上下文了解自身之外的更改,最简单的方法是再次创建新上下文和查询。另一种方法是通过yourContext.Entry<YourEntityType>(entityInstance).Reload();告诉上下文显式从db重新加载实体。

答案 1 :(得分:1)

我的猜测是,您的DbContext与数据库中发生的更改不一致(您说您在Thread.sleep期间正在运行更新)。 DbContext将不会获取这些更新(数据已缓存)。

这就是为什么你希望尽可能缩短上下文的生命周期以减少并发性。这是预期的行为。

请参阅此MSDN post