1

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();
}
1
  • 3
    Please post your GetAvailableItem() and commit() methods. Seems something is wrong in committing Commented Aug 18, 2016 at 12:55

2 Answers 2

4

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

Sign up to request clarification or add additional context in comments.

3 Comments

Good explanation. Now I understand how it works. Etienne also state something very important. The correct practice when working with dbContext is to keep it as short as possible.
Ur wlcm. Also remember: 1. It's not a good practice to returning IQueryable from a repository. 2. It's not a good practice at all, to use repository-pattern, while the DbContext is repository itself.
Oh ya, I am gonna change all of them to return IList. Thanks
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.