Undo changes in entity framework entities
this might be a trivial question but: Since ADO.NET entity framework automatically tracks changes (in generated entities) and therefore keeps the original values, how can I rollback changes made to the entity objects?
I have a form which allows the user to edit a set of "Customer" entities in a grid view.
Now I have two buttons "Accept" and "Revert": if "Accept" is clicked, I call Context.SaveChanges()
and the changed objects are written back to the database. If "Revert" is clicked, I would like for all objects to get their original property values. What would be the code for that?
Thanks
Query ChangeTracker of DbContext for dirty items. Set deleted items state to unchanged and added items to detached. For modified items, use original values and set current values of the entry. Finally set state of modified entry to unchanged:
public void RollBack()
{
var context = DataContextFactory.GetDataContext();
var changedEntries = context.ChangeTracker.Entries()
.Where(x => x.State != EntityState.Unchanged).ToList();
foreach (var entry in changedEntries)
{
switch(entry.State)
{
case EntityState.Modified:
entry.CurrentValues.SetValues(entry.OriginalValues);
entry.State = EntityState.Unchanged;
break;
case EntityState.Added:
entry.State = EntityState.Detached;
break;
case EntityState.Deleted:
entry.State = EntityState.Unchanged;
break;
}
}
}
There is no revert or cancel changes operation in EF. Each entity has ObjectStateEntry
in ObjectStateManager
. State entry contains original and actual values so you can use original values to overwrite current values but you must do it manually for each entity. It will not reveret changes in navigation properties / relations.
The common way to "revert changes" is disposing context and reload entities. If you want to avoid reloading you must create clones of entities and modify those clones in new object context. If user cancel changes you will still have original entities.
dbContext.Entry(entity).Reload();
Accroding to MSDN:
Reloads the entity from the database overwriting any property values with values from the database. The entity will be in the Unchanged state after calling this method.
Note that reverting through the request to database has some drawbacks:
- network traffic
- DB overload
- the increased application response time
This worked for me:
dataContext.customer.Context.Refresh(RefreshMode.StoreWins, item);
Where item
is the customer entity to be reverted.