Entity Framework 中 DbContext 的奇怪行为
Strange Behavior of DbContext in Entity Framework
它是这样的:
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();
}
好的。事情是这样的:
- 正在创建新上下文。
- 通过调用
GetAvailableItem()
从数据库加载项目
- 上下文将加载它们,并缓存它们。
- 正在通过上下文更新项目。所以:数据库行已更新,缓存版本也已更新。
- 在上下文之外(通过 SSMS)通过纯 sql 更新项目。所以:数据库行已更新。但是,由于您使用的上下文与以前相同,并且它有自己的项目版本,并且它无法知道自身外部发生了什么,因此缓存的项目版本保持原样:未更新.
如果你想让你的上下文知道自身之外的变化,最简单的方法是创建一个新的上下文并再次查询。另一种方法是通过 yourContext.Entry<YourEntityType>(entityInstance).Reload();
显式告诉上下文从数据库重新加载实体。
我的猜测是您的 DbContext
与您在数据库中发生的更改不是最新的(您说您是 运行 Thread.sleep
期间的更新)。 DbContext
不会获取这些更新(数据已缓存)。
这就是为什么您希望上下文的生命周期尽可能短以减少并发性。这是预期的行为。
看到这个MSDN post
它是这样的:
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();
}
好的。事情是这样的:
- 正在创建新上下文。
- 通过调用
GetAvailableItem()
从数据库加载项目
- 上下文将加载它们,并缓存它们。
- 正在通过上下文更新项目。所以:数据库行已更新,缓存版本也已更新。
- 在上下文之外(通过 SSMS)通过纯 sql 更新项目。所以:数据库行已更新。但是,由于您使用的上下文与以前相同,并且它有自己的项目版本,并且它无法知道自身外部发生了什么,因此缓存的项目版本保持原样:未更新.
如果你想让你的上下文知道自身之外的变化,最简单的方法是创建一个新的上下文并再次查询。另一种方法是通过 yourContext.Entry<YourEntityType>(entityInstance).Reload();
显式告诉上下文从数据库重新加载实体。
我的猜测是您的 DbContext
与您在数据库中发生的更改不是最新的(您说您是 运行 Thread.sleep
期间的更新)。 DbContext
不会获取这些更新(数据已缓存)。
这就是为什么您希望上下文的生命周期尽可能短以减少并发性。这是预期的行为。
看到这个MSDN post