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.
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.
Disposing and recreating the context is the way to go.
Related
When a user hits the button, I'm executing the following code.
using (Context context = new Context())
{
foreach (Thing thing ViewModel.Things)
context.Things.AddOrUpdate(thing);
context.SaveChanges();
}
The updates are executed except for when the user selected a row and hit delete button. Visually, that post is gone but it's not really being removed from the database because it's not in the view model anymore. Hence, the loppification only ticks for the remaining things and not touching the removees.
I can think of two ways to handle that. One really bad - to remove everything from the context, save it and then recreate based on the view model. It's an idiotic solution so I'm only mentioning it for the reference's sake.
The other is to store each removed post in an array. Then, when the user invokes the code above, I could additionally perform the deletion of the elements in that array. This solution requires me to build the logic for that and I'm having this sense that it should be done automagically for me, if I ask nicely.
Am I right in my expectation and if so, how should I do it? If not, is there a smarter way to achieve my goal than creating this kill squad array?
At the moment, I do a double loop, first adding and updating what's left in the data grid. Then, removing anything that isn't found there. It's going to be painful if the number of elements grows. Also, for some reason I couldn't use Where because I need to rely on Contains and EF didn't let me do that. Not sure why.
using (Context context = new Context())
{
foreach (Thing thing in ViewModel.Things)
context.Things.AddOrUpdate(driver);
foreach (Thing thing in context.Things)
if (!ViewModel.Things.Contains(thing))
context.Things.Remove(thing);
context.SaveChanges();
}
The first thing I want to advice you is you should use the AddOrUpdate extension method only for seeding migrations. The job of AddOrUpdate is to ensure that you don’t create duplicates when you seed data during development.
The best way to achieve what you need you can find it in this link.
First in your ViewModel class you should have an ObservableCollection property of type Thing:
public ObservableCollection<Thing> Things {get;set;}
Then in the ViewModel's constructor (or in another place), you should set the Things property this way:
context.Things.Load();
Things = context.Things.Local;
From the quoted link:
Load is a new extension method on IQueryable that will cause the
results of the query to be iterated, in EF this equates to
materializing the results as objects and adding them to the DbContext
in the Unchanged state
The Local property will give you an ObservableCollection<TEntity> that
contains all Unchanged, Modified and Added objects that are currently
tracked by the DbContext for the given DbSet. As new objects enter the
DbSet (through queries, DbSet.Add/Attach, etc.) they will appear in
the ObservableCollection. When an object is deleted from the DbSet it
will also be removed from the ObservableCollection. Adding or Removing
from the ObservableCollection will also perform the corresponding
Add/Remove on the DbSet. Because WPF natively supports binding to an
ObservableCollection there is no additional code required to have two
way data binding with full support for WPF sorting, filtering etc.
Now to save changes, the only you need to do is create a command in your ViewModel class that call SaveThingsChanges method:
private void SaveThingsChanges()
{
context.SaveChanges();
}
I am having trouble understanding at a fundamental level how a one to many relationship should be managed in Entity Framework. In my application I have two tables, DISPLAY_MASTER, and DISPLAY_ITEMS. Their relationship is like so:
DISPLAY_MASTER.DISPLAY_ID 1----->* DISPLAY_ITEMS.DISPLAY_ID
Entity Framework organizes this really intuitively. I am left with a strongly typed DISPLAY_MASTER object that has an ICollection property called DISPLAY_ITEMS.
My confusion lies within how to save the DISPLAY_ITEMS collection back to the database. In my application I am reading in all of the DISPLAY_ITEMS for the particular DISPLAY_MASTER using LINQ into a List<DISPLAY_ITEMS> object called _displayItems. This is then bound to a DataGrid for editing using MVVM. The user can edit existing DISPLAY_ITEMS, delete existing DISPLAY_ITEMS, or add new DISPLAY_ITEMS using the DataGrid. My binding works perfectly and these changes are reflected in _displayItems. Once it comes time to save is where I stop feeling confident in my code. When the user clicks save I am setting the DISPLAY_MASTER's ICollection like so:
_displayMaster.DISPLAY_ITEMS = _displayItems;
Is this the proper way to be working on an Entity Framework collection? Or should I be binding the DataGrid directly to the _displayMaster.DISPLAY_ITEMS object? Or some other method? The reason I am not confident is because if I try to validate the _displayMaster.DISPLAY_ITEMS entity using:
DbEntityValidationResult validationResults = _context.Entry(_displayMaster.DISPLAY_ITEMS).GetValidationResult();
I get an error saying 'List1' is not part of the collection, which obviously doesn't seem right.
Any advice or guidance would be appreciated.
Thanks.
It depends.
If you disconnect the entities from their database context when you bind them to the grid (i.e. if you dispose the context after loading the entities and create a new context when it comes to save the changes) then it's not so easy. You will have to load the master including the old items from the database, merge the changes into that collection based on your new edited collection from the grid and then save the changes. An example how to do that is here.
If you keep the entities attached to the context you have loaded them into while the user is editing it's much easier if you just directly bind _displayMaster.DISPLAY_ITEMS to the grid because EF is then able to track all the changes you are performing on the collection and update the object graph automatically to the database when you call SaveChanges.
Since you tagged the question with WPF you might have the second option (depending on your application's architecture). In web applications for example the second option doesn't exist at all because all editing happens in a browser which is disconnected of course from the context.
What is the best way to refresh data in Entity Framework 5? I've got an WPF application showing statistics from a database where data is changing all the time. Every 10 seconds the application is updating the result but the default behaviour for EF seems to be to cache the previous results. I would thus like a way to invalidate the previous results so a new set of data can be loaded.
The context of interest is defined in the following way:
public partial class MyEntities: DbContext
{
...
public DbSet<Stat> Stats { get; set; }
...
}
After some reading I was able to find a few approaches, but I have no idea of how efficient these ways are and if they come with downsides.
Create a new instance of the entities object
using (var db = new MyEntities())
{
var stats = from s in db.Stats ...
}
This works but feels inefficient because there are many other places where data is retrieved, and I don't want to reopen a new connection every time I need some data. Wouldn't it be more efficient to keep the connection open and do it another way?
Call refresh on the ObjectContext
var stats = from s in db.Stats ...
ObjectContext.Refresh(RefreshMode.StoreWins, stats );
This also assumes I'm extracting ObjectContext from the dbContext in this way:
private MyEntities db = null;
private ObjectContext ObjectContext
{
get
{
return ((IObjectContextAdapter)db).ObjectContext;
}
}
This is the solution I'm using as it is now. It seems simple. But I read somewhere that ObjectContext nowadays isn't directly accessible in DbContext because the EF team doesn't think that anyone would need it, and that you can do all things you need directly in DbContext. This makes me think that maybe this is not the best way to do it, or?
I know there is a reload method of dbContext.Entry but since I'm not reloading a single entity but rather retrieve a list of entities, I don't really know if this way will work. If I get 5 stat objects in the first query, save them in a list and do a reload on them when it's time to update, I might miss out others that have been added to the list on the database. Or have I completely misunderstood the reload method? Can I do a reload on a DbSetspecified in MyEntities?
There are a number of questions above but what I mainly want to know is what is the best practice in EF5 for asking the same query to the database over and over again? It might very well be something that I haven't discovered yet...
Actually, and even if it seems counter intuitive, the first option is the correct one, see this
DbContext are design to have short lifespans, hence their instantiation cost is quite low compared to the cost of reloading everything, it's mostly due to things like caching, and their data loading designs in general.
That's also why EF works so "naturally" well with ASP .NET MVC, since the DbContext is instantiated at each request.
That doesn't mean you have to create DbContext all over the place of course, in your context, using a DbContext per update operation (the one happening every 10secs) seems good enough, if during that operation you would need to delete a particular row, for example, you would pass the DbContext around, not create a new one.
We're implementing Entity Framework inside a winforms application using DbContext/Code First and have the following question regarding the proper way to check/handle when an entity has been deleted/updated in another context.
For example, we have some auxiliary table data (e.g. StateCodes) and the user could go in another and add/remove states as needed. This auxiliary editor form utilizes it's own DbContext and saves the changes once the user exits the form. Upon returning to the main form, the main context is unaware of the changes made to the database so we'd like to reload the DbSet for the entity. Unfortunately, it appears that if we remove the "MI" state code it still exists in the Local property of the DbSet with an EntityState of unchanged even after we call "Load" to bring in everything.
Outside of completely disposing of the main context would the following be the best way to check and see if what entities have been removed from the database?
foreach (State state in db.States.Local)
{
DbEntityEntry entry = db.Entry(state);
DbPropertyValues databaseValues = entry.GetDatabaseValues();
if (databaseValues == null)
{
db.States.Remove(state);
}
else
{
entry.OriginalValues.SetValues(databaseValues);
}
}
Thank you for your help
You shouldn't keep the context live past its unit of work. The context should only survive as long as its needed, otherwise you're bound to run in to caching pitfalls like you're observing. (Also, the context really isn't that heavy where instantiating it when you need it is overly time-consuming/resource intensive).
If you really must keep it alive, you may want to look in to passing the context to the auxiliary form.
Mirrored from my comment, figured it's best served as an answer
First, what Brad said. Only keep the context alive for the specific unit of work and dispose it. Not doing this will lead to nothing but headaches.
You can also check the entity's state by using the ObjectStateManager and pass in the object or entity key. You can also use the
public void Refresh(
RefreshMode refreshMode,
IEnumerable collection
)
method off of the Context. Also, you can check the entry state.
http://msdn.microsoft.com/en-us/library/bb503718.aspx
I hope you can help me out, I've being scratching my head the whole night trying to figure out where this bug persist.
I'm writing an invoicing application in winform.
I have a grid on the form with its data source set to a BindingList object.
Let's just it's along the lines of:
BindingList<InvoiceLine> MyInvoiceLines = new BindingList<InvoiceLine> { };
Invoice MyInvoice = new Invoice();
Both InvoiceLine and Invoice are entity objects in my model.
I add lines to the grid via:
MyInvoiceLines.Add(new InvoiceLine());
I remove lines from the grid via:
MyInvoiceLines.Remove(LineToBeRemoved);
Where LineToBeRemoved is a property that gets the selected line when use wants to remove the line etc...
So eventually I want to save the invoice, so I do this...
foreach(var line in MyInvoiceLines)
{
MyInvoice.InvoiceLines.Add(line);
}
and then calls SaveChange(). However the lines that was removed from InvoiceLines BindingList are also saved... I've being scratching my head trying to work this out as NO WHERE in my code from start to finish does the InvoiceLines collection gets referenced or was connected with the data context object before this method which eventually action the save.
This is a simplified version of my code but I can't help thinking I must got some thing conceptually wrong either with the BindingList or with the data context object. It really isn't obvious for me as I'm a noob.
Any help would be appreciated, not after a fix, maybe some tools or method where I can further diagnose this problem...
Update: detaching the item before adding to the BindingList seemingly fixed it but deleting the object from entity has strange behaviours :/ thanks everyone.
You could try deleting the object explictly. i.e.
foreach(var object in deletedObjectCollection)
{
_currentContext.DeleteObject(order);
}
rather than rely on it's absence in a collection to activate a delete. In my experience (with EF4) that doesn't work. I use lazy loading and the absence of an object in the collection could be because it hasn't been loaded so it doesn't feel right to rely on it's absence. There is probably (almost certainly) more elegant ways to do this but it is currently working for me.
Generally I've had to do a lot more explicitly with EF than I though i would.
The entity that has been removed from the BindingList, has at also bee detached from the DBContext?
If the entity is still attached to the context it will still be tracked and therefore changes will be saved.
I think you have to set one dirty flag for unchanged record and then check it in Entity.SaveChages() event.
May be this help to you...
You do this multiple times? You may have added all the InvoiceLine items to your Invoice, then removed some from the BindingList (not your actual entity!), and then re-add them to your entity.
I suppose (but to be honest I'm a little unsure about this point) as the primary keys match, duplicates aren't saved twice. However, the items that are supposed to be removed are still there.
If your Invoice object is an Entity object it is context-aware and will be tracked by the context. Calling SaveChanges() will save all changes for all Entity objects unless they are detached.
Keep in mind that if you relate these Entity objects to an object graph and attach any node of the object graph to the context, the entire graph will be attched. So if you create a new entity object, like an InvoiceLine, and you relate this new InvoiceLine to an object graph:
MyInvoiceLines.Add(new InvoiceLine());
the entire graph should be tracked by the context at this point.