web-dev-qa-db-ja.com

Linq to SQL DataContextのすべての変更を拒否するにはどうすればよいですか?

Linq to SQLのDataContextでは、SubmitChanges()を呼び出してすべての変更を送信できます。

私が欲しいのは、どういうわけか、データコンテキスト内のすべての変更を拒否し、すべての変更をロールバックすることです(データベースに移動せずに望ましい)。

これは可能ですか?

44

.net 3.0では、更新されたアイテムにはdb.GetChangeSet().Updates.Clear()、新しいアイテムにはdb.GetChangeSet().Inserts.Clear()、削除されたアイテムにはdb.GetChangeSet().Deletes.Clear()を使用します。

.net 3.5以降では、GetChangeSet()の結果は読み取り専用になり、forまたはforeachでコレクションをループし、maciasがコメントに書いたように、すべてのChangeSetテーブルを更新します。

10

データコンテキストを破棄して、単に新しいインスタンスで置き換えるのはどうですか。

31
Haacked
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-保留中の変更を破棄 を参照してください

18
Teddy

Haackedが言ったように、データコンテキストを削除するだけです。

おそらく、データコンテキストを長期間存続させるべきではありません。これらは、トランザクション方式で使用されるように設計されています(つまり、アトミック作業単位ごとに1つのデータコンテキスト)。データコンテキストを長期間存続させると、古いエンティティを更新するときに同時実行例外が発生するリスクが高くなります。

9
Richard Poole

Updates、Deletes、およびInsertsコレクションでClear()を呼び出しても機能しません。

GetOriginalEntityState()は便利ですが、実際のエンティティではなく、外部キー関係のIDのみを提供するため、分離されたオブジェクトが残ります。

データコンテキストから変更を破棄する方法を説明する記事を次に示します。 http://graemehill.ca/discard-changes-in-linq-to-sql-datacontext

編集:Refresh()を呼び出すと、更新が取り消されますが、削除と挿入は行われません。

9
Graeme Hill

更新は機能しますが、リセットするエンティティを指定する必要があります。

例えば

dataContext.Refresh(RefreshMode.OverwriteCurrentValues, someObject);
4
David Basarab

GetOriginalEntityState(..)を使用して、オブジェクトの元の値を取得できます。古いキャッシュ値を使用しているお客様。

変更を繰り返すこともできます。パフォーマンスのペナルティが高くなるため、テーブル全体ではなく特定のオブジェクトのみを更新および更新します。

foreach (Customer c in MyDBContext.GetChangeSet().Updates)
        {
            MyDBContext.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, c);
        }

これにより、データベースの永続データを使用して変更が元に戻ります。

別の解決策は、Dispose()を使用して、使用するデータコンテキストをダンプすることです。

いずれの場合でも、コレクションのInsertメソッドとRemoveメソッドをオーバーライドすることをお勧めします。使用して追加した顧客(例: InsertOnSubmit()呼び出し。これにより、保留中の挿入と削除に関する問題が解決します。

3

私のアプリケーションは、アクティブなフォーム(ListBox)を選択するためのアイコンを備えたOutlookスタイルです。ユーザーがコンテキストを変更できるようにする前に、変更を受け入れるか破棄する必要があります。

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
    }
}
1
Kyght

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
1
Scott

ここに私がそれをした方法があります。上記のTeddyの例に従って、単純化しました。質問が1つありますが、なぜDELETEの更新に煩わされるのでしょうか。

  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;
  }
0
M Moore