简体   繁体   English

实体框架中DbContext的奇怪行为

[英]Strange Behavior of DbContext in Entity Framework

It goes like this: 它是这样的:

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

Is this the behavior by design? 这是设计使然吗?

Why? 为什么? Is it because DbContext cache the entity and never refresh even if you run the same query again? 是否因为DbContext缓存了实体并且即使再次运行相同的查询也从不刷新?


UPDATE 更新

Here is the code in my repo: 这是我的仓库中的代码:

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

OK. 好。 This is what happening: 这是发生了什么:

  1. Creating a new context. 创建一个新的上下文。
  2. Loading items from db by calling GetAvailableItem() 通过调用GetAvailableItem()从数据库加载项目
  3. Context will load them, and also cache them. 上下文将加载它们并缓存它们。
  4. Updating items via context. 通过上下文更新项目。 So: the db rows ARE updated, and the cached versions ARE updated too. 因此:db行已更新,并且缓存版本也已更新。
  5. Updating items via pure sql, outside the context (through SSMS). 在上下文外部(通过SSMS)通过纯sql更新项目。 So: the db rows ARE updated. 因此:数据库行已更新。 But, since you are using the same context as before, and it has it's own version of items, and there is no way for it to know what's happening outside itself, so the cached version of items, stays how they were: ARE NOT updated. 但是,由于您使用的上下文与以前相同,并且它具有项目的自身版本,因此无法知道自身外部发生的情况,因此,项目的缓存版本将保持原样:不会更新。

If you want to your context know the changes outside itself, the easiest way is to create a new context and query again. 如果您想让上下文知道自身外部的变化,最简单的方法是创建一个新的上下文并再次查询。 Another way is to tell context explicity to re-load entities from db by yourContext.Entry<YourEntityType>(entityInstance).Reload(); 另一种方法是通过yourContext.Entry<YourEntityType>(entityInstance).Reload();告诉上下文明确地从db重新加载实体yourContext.Entry<YourEntityType>(entityInstance).Reload(); .

My guess is that your DbContext is not up to date with your changes that happened in the Database (you said that you are running an update during the Thread.sleep ). 我的猜测是您的DbContext尚未与数据库中发生的更改保持最新(您说过您正在Thread.sleep中运行更新)。 DbContext won't pick up these updates (the data is cached). DbContext将不会接收这些更新(数据已缓存)。

That's why you want to have your lifescope of your context as short as possible to reduce concurrency. 这就是为什么您希望对上下文的生命周期尽可能短以减少并发性。 This is an expected behavior. 这是预期的行为。

See this MSDN post 看到这个MSDN帖子

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM