2

I have an EF5 WPF/MVVM solution that's working without problems. The project is an order entry system but loading an order loads lots of related items so the context is used to track all the changes and then save it off, so the context is long lived. If user A loads an order and doesn't do anything with it, and then User B loads that order and updates it I have a refresh button that was intended to let User A update the stale data. Unfortunately, I can't seem to get EF5 to ignore the cache. I originally thought this would work:

   _trackingContext.GetObjectContext().Refresh(RefreshMode.StoreWins, theOrders);
   List<OrderLineItem> line_items = theOrders.SelectMany(x => x.OrderLineItems).ToList();
   _trackingContext.GetObjectContext().Refresh(RefreshMode.StoreWins, line_items);

Where GetObjectContext() is just a wrapper

public ObjectContext GetObjectContext()
{
    return (this as IObjectContextAdapter).ObjectContext;
}

Turns out this doesn't update the data. So I thought maybe I had to change the Merge option so I added

var set = _trackingContext.GetObjectContext().CreateObjectSet<OrderLineItem>();
set.MergeOption = MergeOption.OverwriteChanges;

and I also tried it for Orders (and with the PreserveChanges option) but nothing worked. Eventually, I just resorted to disposing and recreating the context and then recreating the search selection but it seems like this should be overkill. Is there some easier way to just get EF5 to update any stale data with fresh data from the database?

Update

OK - It turns out it was a testing methodology problem. After seeing @jure's reply and implementing it, and having it appear to not work I finally got smart. I broke out SQL Profiler. The right things were happening behind the scenes but I wasn't doing the right thing to update the view. Once I did that my original code worked.

Tod
  • 8,192
  • 5
  • 52
  • 93
  • This might be what you're looking for... http://stackoverflow.com/questions/1746941/objectcontext-refresh (or if you want to refresh everything... http://msdn.microsoft.com/en-us/library/bb503718.aspx) – Basic Apr 30 '13 at 20:57
  • Just don't use contexts with a long lifetime. Your issue is only one of the problems you'll face. – Gert Arnold Apr 30 '13 at 22:18
  • 1
    I see that advice a lot now, but it seems to me that if I want EF to manage all the related records during the order entry process I have to keep the context alive (this is a desktop app). It seemed like a lot of the value of EF was having it manage the related graph of data. Maybe I missed something fundamental about how to get all state management from EF with short-lived contexts. – Tod Apr 30 '13 at 22:43
  • @Basic I had seen the other SO post, but the approach of using `GetObjectStateEntries()` didn't work. I've also previously read the MSDN docs which is why I thought `Refresh(RefreshMode.StoreWins)` would do the trick but no such luck. – Tod Apr 30 '13 at 23:15
  • 2
    Re: Having short-lived contexts, use other objects to store what will comprise your order until you're ready to make changes, then apply them in one go. My experience is primarily in web apps but in this scenario, I'd use DTOs which describe the order and then have an `Update()` method which takes the DTO, finds the appropriate records, applies the update and commits. This allows you to separate the Data layer from the UI. – Basic Apr 30 '13 at 23:18

2 Answers2

9

There's a Reload method in the DbEntityEntry class, so you could do:

dbContext.Entry(entity).Reload();

but that is only for one object in the context that you need to refresh from Db.

Jurica Smircic
  • 6,117
  • 2
  • 22
  • 27
  • Your reply led me to the answer. Plus it's a nice way to get find control over the refresh process I can reload the order and then foreach over the line items. If any are dirty I can skip them and get the same effect as Preserve changes. Thanks for the reminder about Reload. – Tod Apr 30 '13 at 23:46
0

Disposing and recreating the context is the way to go.

gabnaim
  • 1,103
  • 9
  • 13