Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Undo changes in entity framework entities

People also ask

How do I undo changes in Entity Framework?

To rollback changes we can use this behavior of the SaveChanges method. Just change the entity state from Modified to Unchanged, Added to Detached and reload the entity if its state is Deleted. This way is very useful when we need to rollback the changes of a specific entity or specific entities from DbContext.

When would you use SaveChanges false AcceptAllChanges ()?

Sometimes though the SaveChanges(false) + AcceptAllChanges() pairing is useful. The most useful place for this is in situations where you want to do a distributed transaction across two different Contexts. If context1. SaveChanges() succeeds but context2.

What is Dbcontexttransaction?

Wraps access to the transaction object on the underlying store connection and ensures that the Entity Framework executes commands on the database within the context of that transaction. An instance of this class is retrieved by calling BeginTransaction() on the DbContextDatabase object.

What is Entitystate detached?

An entity is in this state immediately after it has been created and before it is added to the object context. An entity is also in this state after it has been removed from the context by calling the Detach(Object) method or if it is loaded by using a NoTrackingMergeOption.


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.


Easy way without tracking any changes. It should be faster than looking at every entities.

public void Rollback()
{
    dataContext.Dispose();
    dataContext= new MyEntities(yourConnection);
}

// Undo the changes of all entries. 
foreach (DbEntityEntry entry in context.ChangeTracker.Entries()) 
{ 
    switch (entry.State) 
    { 
        // Under the covers, changing the state of an entity from  
        // Modified to Unchanged first sets the values of all  
        // properties to the original values that were read from  
        // the database when it was queried, and then marks the  
        // entity as Unchanged. This will also reject changes to  
        // FK relationships since the original value of the FK  
        // will be restored. 
        case EntityState.Modified: 
            entry.State = EntityState.Unchanged; 
            break; 
        case EntityState.Added: 
            entry.State = EntityState.Detached; 
            break; 
        // If the EntityState is the Deleted, reload the date from the database.   
        case EntityState.Deleted: 
            entry.Reload(); 
            break; 
        default: break; 
    } 
} 

It worked for me. However you must to reload your data from the context to bring the old data. Source here


As for me, better method to do it is to set EntityState.Unchanged on every entity you want to undo changes on. This assures changes are reverted on FK and has a bit more clear syntax.