Terrence Terrence - 1 year ago 43
C# Question

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


// 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?


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

Answer Source

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