我怎样才能拒绝Linq到SQL的DataContext中的所有更改?
在Linq到SQL的DataContext上,我可以调用SubmitChanges()来提交所有更改。
我想要的是以某种方式拒绝datacontext中的所有更改,并回滚所有更改(最好不去数据库)。
这可能吗?
在.net 3.0中使用db.GetChangeSet().Updates.Clear()
获取已更新的db.GetChangeSet().Inserts.Clear()
或db.GetChangeSet().Deletes.Clear()
已删除的项目。
在.net 3.5及更高版本中,GetChangeSet()的结果现在是只读的,在for循环或foreach循环集合,并像在他的评论中写的macias一样刷新每个ChangeSet表。
为什么不放弃数据上下文,并简单地将其replace为新的实例?
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); } } }
请参阅Linq to SQL – 放弃挂起的更改
正如Haacked所说,只要放弃数据上下文。
您可能不应该保持长时间的数据上下文。 它们被devise成以交易方式使用(即每个primefaces工作单元一个数据上下文)。 如果您长时间保持数据上下文处于活动状态,那么当您更新陈旧的实体时,运行产生并发exception的风险会更大。
在更新,删除和插入集合上调用Clear()不起作用。
GetOriginalEntityState()可以是有用的,但它只给出外键关系的ID,而不是实际的实体,所以你留下了一个分离的对象。
这里有一篇文章解释了如何从数据上下文中放弃更改: http : //graemehill.ca/discard-changes-in-linq-to-sql-datacontext
编辑:调用刷新()将撤消更新,但不会删除和插入。
刷新将工作,但是你必须给你想要重置的实体。
例如
dataContext.Refresh(RefreshMode.OverwriteCurrentValues, someObject);
您可以使用GetOriginalEntityState(..)获取对象的原始值,例如客户使用旧的caching值。
您也可以遍历所做的更改,例如更新并仅刷新特定对象,而不是整个表,因为性能损失很高。
foreach (Customer c in MyDBContext.GetChangeSet().Updates) { MyDBContext.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, c); }
这将使用数据库中的持久数据恢复更改。
另一个解决scheme是使用Dispose()来转储您使用的datacontext。
在任何情况下,重写例如您使用的客户的集合中的插入和移除方法并添加例如InsertOnSubmit()调用是一个好习惯。 这将解决您的问题与待处理的插入和删除。
我的应用程序是Outlook风格的图标来select一个活动的窗体(列表框)。 在允许用户改变他们的上下文之前,他们必须接受改变或丢弃它们。
var changes = db.GetChangeSet(); if ((changes.Updates.Count > 0) || (changes.Inserts.Count > 0) || (changes.Deletes.Count > 0)) { if (MessageBox.Show("Would you like to save changes?", "Save Changes", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { db.SubmitChanges(); } else { //Rollback Changes foreach (object objToInsert in changes.Inserts) { db.GetTable(objToInsert.GetType()).DeleteOnSubmit(objToInsert); } foreach (object objToDelete in changes.Deletes) { db.GetTable(objToDelete.GetType()).InsertOnSubmit(objToDelete); } foreach (object objToUpdate in changes.Updates) { db.Refresh(RefreshMode.OverwriteCurrentValues, objToUpdate); } CurrentForm.SetObject(null); //Application Code to Clear active form RefreshList(); //Application Code to Refresh active list } }
优秀的写在这里 ,但这里是一个复制和粘贴使用的代码。
Public Sub DiscardInsertsAndDeletes(ByVal data As DataContext) ' Get the changes Dim changes = data.GetChangeSet() ' Delete the insertions For Each insertion In changes.Inserts data.GetTable(insertion.GetType).DeleteOnSubmit(insertion) Next ' Insert the deletions For Each deletion In changes.Deletes data.GetTable(deletion.GetType).InsertOnSubmit(deletion) Next End Sub Public Sub DiscardUpdates(ByVal data As DataContext) ' Get the changes Dim changes = data.GetChangeSet() ' Refresh the tables with updates Dim updatedTables As New List(Of ITable) For Each update In changes.Updates Dim tbl = data.GetTable(update.GetType) ' Make sure not to refresh the same table twice If updatedTables.Contains(tbl) Then Continue For Else updatedTables.Add(tbl) data.Refresh(RefreshMode.OverwriteCurrentValues, tbl) End If Next End Sub
这是我如何做到的。 我只是跟着泰迪的例子,简化了它。 我有一个问题,为什么还要在DELETES刷新呢?
public static bool UndoPendingChanges(this NtsSuiteDataContext dbContext) { if (dbContext.ChangesPending()) { ChangeSet dbChangeSet = dbContext.GetChangeSet(); dbContext.Refresh(RefreshMode.OverwriteCurrentValues, dbChangeSet.Deletes); dbContext.Refresh(RefreshMode.OverwriteCurrentValues, dbChangeSet.Updates); //Undo Inserts foreach (object objToInsert in dbChangeSet.Inserts) { dbContext.GetTable(objToInsert.GetType()).DeleteOnSubmit(objToInsert); } //Undo deletes foreach (object objToDelete in dbChangeSet.Deletes) { dbContext.GetTable(objToDelete.GetType()).InsertOnSubmit(objToDelete); } } return true; }