Discard Changes Without Disposing DbContext/ObjectContext in Entity Framework 6

Introduction


All changes in entities can be committed to the database by the SaveChanges method of DbContext. It means whatever changes are made to the entities can be committed to the database by this method. Sometimes some of the changes are wrong and we need to roll them back without disposing of the DbContext object. This article explains how to do this.

Solution

There are many way to undo changes from DbContext.

1. Undoing the Changes at DbContext Level

This way is very useful when we need to rollback all changed entities from DbContext. How the SaveChanges method of DbContext works also depends on the entity state. The SaveChanges method does not touch Entities with an Unchanged state so the update is not sent to the database for those entities. Entities with an Added state are inserted into the database and their state becomes Unchanged after returning from the SaveChanges method. The same for entities with a Modified state, they are updated into the database and the state becomes Unchanged after returning from the SaveChanges method and entities with a Deleted state are deleted from the database and the state becomes detached after returning from the SaveChanges method.

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.

Sample code
  1. public static void UndoingChangesDbContextLevel(DbContext context)  
  2. {  
  3.     foreach (DbEntityEntry entry in context.ChangeTracker.Entries())  
  4.     {  
  5.         switch (entry.State)  
  6.         {  
  7.             case EntityState.Modified:  
  8.                 entry.State = EntityState.Unchanged;  
  9.                 break;  
  10.             case EntityState.Added:  
  11.                 entry.State = EntityState.Detached;  
  12.                 break;    
  13.             case EntityState.Deleted:  
  14.                 entry.Reload();  
  15.                 break;  
  16.             defaultbreak;  
  17.         }  
  18.     }   
  19. }  
  20.   
  21. // Test Code  
  22. static void Main(string[] args)  
  23. {  
  24.     using (Entities Context = new Entities())  
  25.     {  
  26.         DepartmentMaster dept = Context.DepartmentMasters.Create();  
  27.         dept.Name = "New Added Department";  
  28.         dept.Code = "AAA";  
  29.         Context.DepartmentMasters.Add(dept);  
  30.   
  31.         //Modify the existing Value  
  32.         DepartmentMaster deptUpdate = Context.DepartmentMasters.Find(1);  
  33.         deptUpdate.Code = "BBB";  
  34.         UndoingChangesDbContextLevel(Context);  
  35.   
  36.         Context.SaveChanges();  
  37.     }  

 2. Undoing Changes at DbEntity level

This way is very useful when we need to rollback the changes of a specific entity or specific entities from DbContext. This method uses the same mechanism as described in the preceding methodology.

Sample code
  1. public static void UndoingChangesDbEntityLevel(DbContext context, object entity)  
  2. {  
  3.     DbEntityEntry entry = context.Entry(entity);  
  4.     switch (entry.State)  
  5.     {  
  6.         case EntityState.Modified:  
  7.             entry.State = EntityState.Unchanged;  
  8.             break;  
  9.         case EntityState.Added:  
  10.             entry.State = EntityState.Detached;  
  11.             break;  
  12.         case EntityState.Deleted:  
  13.             entry.Reload();  
  14.             break;  
  15.         defaultbreak;  
  16.     }  
  17. }  
  18.   
  19. // Test Code  
  20. static void Main(string[] args)  
  21. {  
  22.     using (Entities Context = new Entities())  
  23.     {  
  24.         DepartmentMaster dept = Context.DepartmentMasters.Create();  
  25.         dept.Name = "New Added Department";  
  26.         dept.Code = "AAA";  
  27.         Context.DepartmentMasters.Add(dept);  
  28.   
  29.         //Modify the existing Value  
  30.         DepartmentMaster deptUpdate = Context.DepartmentMasters.Find(1);  
  31.         deptUpdate.Code = "BBB";  
  32.           
  33.         UndoingChangesDbEntityLevel(Context, dept);  
  34.         UndoingChangesDbEntityLevel(Context, deptUpdate);   
  35.         Context.SaveChanges();  
  36.     }  

3. Undo the Change in the DbEntity Property level

This way is very useful when we need to rollback changes of a specific entity or specific entities from DbContext.

This method is more useful for undoing the changes of entities with a Modified state. In this method, we just modify entity's current value to the original value.

Sample code
  1. public static void UndoingChangesDbEntityPropertyLevel(DbContext context, object entity)  
  2. {  
  3.     DbEntityEntry entry = context.Entry(entity);  
  4.     if (entry.State == EntityState.Added || entry.State == EntityState.Detached)  
  5.     {  
  6.         entry.State = EntityState.Detached;  
  7.         return;  
  8.     }  
  9.     if (entry.State == EntityState.Deleted)  
  10.     {  
  11.         entry.Reload();  
  12.     }  
  13.   
  14.     foreach (string propertyName in entry.OriginalValues.PropertyNames)  
  15.     {  
  16.         // Get and Set the Property value by the Property Name.   
  17.         entry.Property(propertyName).CurrentValue = entry.Property(propertyName).OriginalValue;   
  18.     }  
  19. }  
  20.   
  21. // Test Code  
  22. static void Main(string[] args)  
  23. {  
  24.     using (Entities Context = new Entities())  
  25.     {  
  26.         DepartmentMaster dept = Context.DepartmentMasters.Create();  
  27.         dept.Name = "New Added Department";  
  28.         dept.Code = "AAA";  
  29.         Context.DepartmentMasters.Add(dept);  
  30.   
  31.         //Modify the existing Value  
  32.         DepartmentMaster deptUpdate = Context.DepartmentMasters.Find(1);  
  33.         deptUpdate.Code = "BBB";  
  34.   
  35.         UndoingChangesDbEntityPropertyLevel(Context, dept);  
  36.         UndoingChangesDbEntityPropertyLevel(Context, deptUpdate);  
  37.   
  38.         Context.SaveChanges();  
  39.     }  

Undo the Changes of the ObjectContext

Sometimes we are using Entity Framework version 4.1 and above and still we are dealing with ObjectContext, the following method is very useful for undoing the changed entities in that situation.

ObjectContext.Refresh methods are refresh or update data from the data source. After this method is called, the object's original values will be updated with the data source value and will update the current value depending on the RefreshMode value. If the RefreshMode is set to StoreWins, the object is updated from the data source and if RefreshMode is set to ClientWins, the object's properties are not replaced with data source value.

Sample code
  1. public static void UndoingChangesObjectContext(ObjectContext Context)  
  2. {  
  3.     IEnumerable<object> collection = from e in Context.ObjectStateManager.GetObjectStateEntries  
  4.                                 (EntityState.Modified | EntityState.Deleted)  
  5.                                 select e.Entity;  
  6.     Context.Refresh(RefreshMode.StoreWins, collection);  
  7.   
  8.     IEnumerable<object> AddedCollection = from e in Context.ObjectStateManager.GetObjectStateEntries  
  9.                                                 (EntityState.Added)  
  10.                                             select e.Entity;  
  11.     foreach (object addedEntity in AddedCollection)  
  12.     {  
  13.         if (addedEntity != null)  
  14.         {  
  15.             Context.Detach(addedEntity);  
  16.         }  
  17.     }  
  18. }   
  19. // Test Code  
  20. static void Main(string[] args)  
  21. {  
  22.     using (Entities Context = new Entities())  
  23.     {  
  24.         DepartmentMaster dept = Context.DepartmentMasters.Create();  
  25.         dept.Name = "New Added Department";  
  26.         dept.Code = "AAA";  
  27.         Context.DepartmentMasters.Add(dept);   
  28.         //Modify the existing Value  
  29.         DepartmentMaster deptUpdate = Context.DepartmentMasters.Find(1);  
  30.         deptUpdate.Code = "BBB";           
  31.         UndoingChangesObjectContext(((IObjectContextAdapter)Context).ObjectContext);   
  32.         Context.SaveChanges();  
  33.     }  

Summary

I hope this article helps you to understand how we discarding the changes from DbContext or ObjectContext can be done.