Linq to SQL - 撤销所有未提交的改动
在某些情况下我们需要撤销/丢弃所有未提交的改动,包括Update, Delete和Insert。context中GetChangeSet()方法可以返回当前所有未提交的改动,而我们的目标是清空Change Set。
撤销Update很简单,通过OverwriteCurrentValues的模式刷新,context中缓存的初始值以及改动后的对象都会被数据库中最新的值覆盖。
对于Insert,只要再调用一次DeleteOnSubmit的方法即可在ChangeSet中移除对象。
Delete则需要首先Refresh一次,然后InsertOnSubmit。
重要的是在这个过程中Linq to SQL会自动比较缓存的初始对象及更新后的对象,操作在内存中进行,并不会产生任何Insert/Update/Delete的数据库操作。
下面代码使用Extension Method将DiscardPendingChanges方法附加到DataContext对象中
public static class DataContextExtensions { /// <summary> /// Discard all pending changes of current DataContext. /// All un-submitted changes, including insert/delete/modify will lost. /// </summary> /// <param name="context"></param> public static void DiscardPendingChanges(this DataContext context) { context.RefreshPendingChanges(RefreshMode.OverwriteCurrentValues); ChangeSet changeSet = context.GetChangeSet(); if (changeSet != null) { //Undo inserts foreach (object objToInsert in changeSet.Inserts) { context.GetTable(objToInsert.GetType()).DeleteOnSubmit(objToInsert); } //Undo deletes foreach (object objToDelete in changeSet.Deletes) { context.GetTable(objToDelete.GetType()).InsertOnSubmit(objToDelete); } } } /// <summary> /// Refreshes all pending Delete/Update entity objects of current DataContext according to the specified mode. /// Nothing will do on Pending Insert entity objects. /// </summary> /// <param name="context"></param> /// <param name="refreshMode">A value that specifies how optimistic concurrency conflicts are handled.</param> public static void RefreshPendingChanges(this DataContext context, RefreshMode refreshMode) { ChangeSet changeSet = context.GetChangeSet(); if (changeSet != null) { context.Refresh(refreshMode, changeSet.Deletes); context.Refresh(refreshMode, changeSet.Updates); } } }
调用时:
DataContext context = new DataContext(); //Do insert/delete/update context.DiscardPendingChanges(); //Will clear DataContext.ChangeSet context.SubmitChanges(); //Nothing will be submit