2

I am a bit confused on the usage of DbContext in Entity Framework. Here's the scenario I'm confused about.

  • I use a linq query from the dbcontext to get data. Something like:

    List<Transactions> transactions = DefaultContext.Transactions.ToList();
    
  • Then I update a column in one of the transactions returned in that query directly in the database.

  • Then I call again:

    List<Transactions> transactions = DefaultContext.Transactions.ToList();
    

When the list returns back this time, it doesn't reflect the updates/changes I made when running the update statement, unless I loop through all my transactions and Reload them:

foreach (DbEntityEntry<Transactions> item in DefaultContext.ChangeTracker.Entries<Transactions>())
{
    DefaultContext.Entry<Transactions>(item.Entity).Reload();
}

Is this normal behavior? I assume that on my initial query, they are attached to the object context. Then when I query the second time, it doesn't make a trip to the database, and just pulls out the entities from the object context, unless I clear/detach or individually reload all of the entities.

mservidio
  • 12,817
  • 9
  • 58
  • 84

3 Answers3

8

It is normal and in case of DbContext API fixed behaviour because from some very strange reason neither DbSet or DbQuery expose MergeOption property. In case of ObjectContext API you can set the behaviour by MergeOption exposed on ObjectSet and ObjectQuery. So if you want to refresh values from database (and lose your changes) you can do:

ObjectContext objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
ObjectSet<Transactions> set = objectContext.CreateObjectSet<Transactions>();
set.MergeOption = MergeOption.OverwriteChanges;
List<Transactions> transactions = set.ToList();

If you just want to refresh transactions but you don't want to lose your changes you can use MergeOption.PreserveChanges instead.

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • I need to filter some of the data returned. I was using a .Where(... before, however now that I'm using ObjectContext, it's not aware of my entity classes. How do I filter the data now on the query though? I don't want to return back the entire result. – mservidio Aug 17 '11 at 21:02
  • What you mean by "it's not aware of my entity classes". You can write same linq query with ObjectContext as you did with DbContext. – Ladislav Mrnka Aug 17 '11 at 21:04
2

That depends on the MergeOption of the DefaultContext.Transactions query. The default value, AppendOnly, won't overwrite objects already in your context. You can change this to OverwriteChanges to get the behavior you're expecting.

Craig Stuntz
  • 125,891
  • 12
  • 252
  • 273
  • Thanks for pointing this out. As I'm using DbContext, my queries aren't of type ObjectQuery though. So I can't cast a query like var query = Defaultcontext.Transactions; to ((ObjectQuery)query).MergeOption = MergeOption.OverwriteChanges; Do I need to use a linq style query instead? – mservidio Aug 17 '11 at 20:54
1

Related to the above, this is where I landed when I had this same error. But I wanted in my case to set Merge Option to No Tracking. I ran into this when I had an excel export method that was attempting to turn off object tracking of an IQueryable. Moving through lots of data that I wasn't going to be changing, I didn't need any change tracking.

A line of code similar to the below would fail on attempting to cast some IQueryables to class ObjectQuery (but succeed on others.)

var y = ((ObjectQuery)query).MergeOption = MergeOption.NoTracking;

Instead, I replaced this with usage of AsNoTracking

query = query.AsNoTracking();

Relating back to the original question, this would be potentially like the below, Extention method on DBQuery added in System.Data.Entity

List<Transactions> transactions = DefaultContext.Transactions.AsNoTracking().ToList();

Semi-Related Article: https://msdn.microsoft.com/en-us/library/hh949853(v=vs.113).aspx

Greg
  • 2,410
  • 21
  • 26