在Linq to SQL的DataContext上,我可以调用SubmitChanges()来提交所有更改。
我想要的是以某种方式拒绝datacontext中的所有更改并回滚所有更改(最好不要转到数据库)。
这可能吗?
答案 0 :(得分:30)
为什么不丢弃数据上下文并简单地用新实例替换它?
答案 1 :(得分:18)
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);
}
}
}
答案 2 :(得分:10)
在.net 3.0中,使用db.GetChangeSet().Updates.Clear()
进行更新,db.GetChangeSet().Inserts.Clear()
代表新内容,db.GetChangeSet().Deletes.Clear()
代表已删除的内容。
在.net 3.5及更高版本中,GetChangeSet()的结果现在是readonly,将集合循环到for或foreach并刷新每个ChangeSet表,就像macias在他的评论中写的那样。
答案 3 :(得分:9)
正如Haacked所说,只需删除数据上下文。
您可能不应该长时间保持数据上下文存活。它们被设计成以事务方式使用(即每个原子工作单元一个数据上下文)。如果长时间保持数据上下文存活,则在更新陈旧实体时会产生更大的生成并发异常的风险。
答案 4 :(得分:9)
在Updates,Deletes和Inserts集合上调用Clear()不起作用。
GetOriginalEntityState()可能很有用,但它只提供外键关系的ID,而不是实际的实体,所以你留下了一个分离的对象。
这篇文章介绍了如何从数据上下文中删除更改:http://graemehill.ca/discard-changes-in-linq-to-sql-datacontext
编辑:调用Refresh()将撤消更新,但不会删除和插入。
答案 5 :(得分:4)
刷新将起作用,但您必须为要重置的实体提供。
例如
dataContext.Refresh(RefreshMode.OverwriteCurrentValues, someObject);
答案 6 :(得分:3)
您可以使用 GetOriginalEntityState(..)来获取对象的原始值,例如客户使用旧的缓存值。
您还可以迭代更改,例如仅更新和刷新特定对象而不是整个表,因为性能损失会很高。
foreach (Customer c in MyDBContext.GetChangeSet().Updates)
{
MyDBContext.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, c);
}
这将使用数据库中的持久数据恢复更改。
另一个解决方案是使用Dispose()转储您使用的datacontext。
在任何情况下,最好覆盖例如集合中的Insert和Remove方法。您使用并添加的客户,例如一个InsertOnSubmit()调用。这将解决您的待处理插入和删除问题。
答案 7 :(得分:1)
在here上写的很好,但这里是所用代码的复制和粘贴。
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
答案 8 :(得分:1)
我的应用程序是outlook样式,带有一个图标来选择一个活动表单(ListBox)。在允许用户更改其上下文之前,他们必须接受更改或丢弃它们。
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
}
}
答案 9 :(得分:0)
我是这样做的。我只是按照上面的Teddy的例子进行了简化。我有一个问题,为什么甚至打扰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;
}