如何拒绝Linq to SQL DataContext中的所有更改?

时间:2008-11-03 16:41:14

标签: linq linq-to-sql

在Linq to SQL的DataContext上,我可以调用SubmitChanges()来提交所有更改。

我想要的是以某种方式拒绝datacontext中的所有更改并回滚所有更改(最好不要转到数据库)。

这可能吗?

10 个答案:

答案 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);
        }
    }
}

请参阅Linq to SQL - Discard Pending Changes

答案 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;
  }