简体   繁体   中英

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?


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()
  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.
  5. Updating items via pure sql, outside the context (through SSMS). 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(); .

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 won't pick up these updates (the data is cached).

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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