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
- public static void UndoingChangesDbContextLevel(DbContext context)
- {
- foreach (DbEntityEntry entry in context.ChangeTracker.Entries())
- {
- switch (entry.State)
- {
- case EntityState.Modified:
- entry.State = EntityState.Unchanged;
- break;
- case EntityState.Added:
- entry.State = EntityState.Detached;
- break;
- case EntityState.Deleted:
- entry.Reload();
- break;
- default: break;
- }
- }
- }
-
-
- static void Main(string[] args)
- {
- using (Entities Context = new Entities())
- {
- DepartmentMaster dept = Context.DepartmentMasters.Create();
- dept.Name = "New Added Department";
- dept.Code = "AAA";
- Context.DepartmentMasters.Add(dept);
-
-
- DepartmentMaster deptUpdate = Context.DepartmentMasters.Find(1);
- deptUpdate.Code = "BBB";
- UndoingChangesDbContextLevel(Context);
-
- Context.SaveChanges();
- }
- }
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
- public static void UndoingChangesDbEntityLevel(DbContext context, object entity)
- {
- DbEntityEntry entry = context.Entry(entity);
- switch (entry.State)
- {
- case EntityState.Modified:
- entry.State = EntityState.Unchanged;
- break;
- case EntityState.Added:
- entry.State = EntityState.Detached;
- break;
- case EntityState.Deleted:
- entry.Reload();
- break;
- default: break;
- }
- }
-
-
- static void Main(string[] args)
- {
- using (Entities Context = new Entities())
- {
- DepartmentMaster dept = Context.DepartmentMasters.Create();
- dept.Name = "New Added Department";
- dept.Code = "AAA";
- Context.DepartmentMasters.Add(dept);
-
-
- DepartmentMaster deptUpdate = Context.DepartmentMasters.Find(1);
- deptUpdate.Code = "BBB";
-
- UndoingChangesDbEntityLevel(Context, dept);
- UndoingChangesDbEntityLevel(Context, deptUpdate);
- Context.SaveChanges();
- }
- }
3. Undo the Change in the DbEntity Property levelThis 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
- public static void UndoingChangesDbEntityPropertyLevel(DbContext context, object entity)
- {
- DbEntityEntry entry = context.Entry(entity);
- if (entry.State == EntityState.Added || entry.State == EntityState.Detached)
- {
- entry.State = EntityState.Detached;
- return;
- }
- if (entry.State == EntityState.Deleted)
- {
- entry.Reload();
- }
-
- foreach (string propertyName in entry.OriginalValues.PropertyNames)
- {
-
- entry.Property(propertyName).CurrentValue = entry.Property(propertyName).OriginalValue;
- }
- }
-
-
- static void Main(string[] args)
- {
- using (Entities Context = new Entities())
- {
- DepartmentMaster dept = Context.DepartmentMasters.Create();
- dept.Name = "New Added Department";
- dept.Code = "AAA";
- Context.DepartmentMasters.Add(dept);
-
-
- DepartmentMaster deptUpdate = Context.DepartmentMasters.Find(1);
- deptUpdate.Code = "BBB";
-
- UndoingChangesDbEntityPropertyLevel(Context, dept);
- UndoingChangesDbEntityPropertyLevel(Context, deptUpdate);
-
- Context.SaveChanges();
- }
- }
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
- public static void UndoingChangesObjectContext(ObjectContext Context)
- {
- IEnumerable<object> collection = from e in Context.ObjectStateManager.GetObjectStateEntries
- (EntityState.Modified | EntityState.Deleted)
- select e.Entity;
- Context.Refresh(RefreshMode.StoreWins, collection);
-
- IEnumerable<object> AddedCollection = from e in Context.ObjectStateManager.GetObjectStateEntries
- (EntityState.Added)
- select e.Entity;
- foreach (object addedEntity in AddedCollection)
- {
- if (addedEntity != null)
- {
- Context.Detach(addedEntity);
- }
- }
- }
-
- static void Main(string[] args)
- {
- using (Entities Context = new Entities())
- {
- DepartmentMaster dept = Context.DepartmentMasters.Create();
- dept.Name = "New Added Department";
- dept.Code = "AAA";
- Context.DepartmentMasters.Add(dept);
-
- DepartmentMaster deptUpdate = Context.DepartmentMasters.Find(1);
- deptUpdate.Code = "BBB";
- UndoingChangesObjectContext(((IObjectContextAdapter)Context).ObjectContext);
- Context.SaveChanges();
- }
- }
Summary
I hope this article helps you to understand how we discarding the changes from DbContext or ObjectContext can be done.