Linq to SQLのDataContextでは、SubmitChanges()を呼び出してすべての変更を送信できます。
私が欲しいのは、どういうわけか、データコンテキスト内のすべての変更を拒否し、すべての変更をロールバックすることです(データベースに移動せずに望ましい)。
これは可能ですか?
.net 3.0では、更新されたアイテムにはdb.GetChangeSet().Updates.Clear()
、新しいアイテムにはdb.GetChangeSet().Inserts.Clear()
、削除されたアイテムにはdb.GetChangeSet().Deletes.Clear()
を使用します。
.net 3.5以降では、GetChangeSet()の結果は読み取り専用になり、forまたはforeachでコレクションをループし、maciasがコメントに書いたように、すべてのChangeSetテーブルを更新します。
データコンテキストを破棄して、単に新しいインスタンスで置き換えるのはどうですか。
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が言ったように、データコンテキストを削除するだけです。
おそらく、データコンテキストを長期間存続させるべきではありません。これらは、トランザクション方式で使用されるように設計されています(つまり、アトミック作業単位ごとに1つのデータコンテキスト)。データコンテキストを長期間存続させると、古いエンティティを更新するときに同時実行例外が発生するリスクが高くなります。
Updates、Deletes、およびInsertsコレクションでClear()を呼び出しても機能しません。
GetOriginalEntityState()は便利ですが、実際のエンティティではなく、外部キー関係のIDのみを提供するため、分離されたオブジェクトが残ります。
データコンテキストから変更を破棄する方法を説明する記事を次に示します。 http://graemehill.ca/discard-changes-in-linq-to-sql-datacontext
編集:Refresh()を呼び出すと、更新が取り消されますが、削除と挿入は行われません。
更新は機能しますが、リセットするエンティティを指定する必要があります。
例えば
dataContext.Refresh(RefreshMode.OverwriteCurrentValues, someObject);
GetOriginalEntityState(..)を使用して、オブジェクトの元の値を取得できます。古いキャッシュ値を使用しているお客様。
変更を繰り返すこともできます。パフォーマンスのペナルティが高くなるため、テーブル全体ではなく特定のオブジェクトのみを更新および更新します。
foreach (Customer c in MyDBContext.GetChangeSet().Updates)
{
MyDBContext.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, c);
}
これにより、データベースの永続データを使用して変更が元に戻ります。
別の解決策は、Dispose()を使用して、使用するデータコンテキストをダンプすることです。
いずれの場合でも、コレクションのInsertメソッドとRemoveメソッドをオーバーライドすることをお勧めします。使用して追加した顧客(例: InsertOnSubmit()呼び出し。これにより、保留中の挿入と削除に関する問題が解決します。
私のアプリケーションは、アクティブなフォーム(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
}
}
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
ここに私がそれをした方法があります。上記の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;
}