В Linq to SQL DataContext я могу вызвать SubmitChanges(), чтобы отправить все изменения.
Я хочу, чтобы каким-то образом отклонить все изменения в datacontext и отменить все изменения (предпочтительнее, не переходя в базу данных).
Возможно ли это?
В Linq to 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 и обновляет каждую таблицу ChangeSet, также как и в своем комментарии macias.
Почему бы не отказаться от контекста данных и просто заменить его новым экземпляром?
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, просто отбросьте контекст данных.
Вероятно, вы не должны долго сохранять контекст данных. Они предназначены для использования транзакционным способом (т.е. Один контекст данных на атомную рабочую единицу). Если вы сохраняете контекст данных в течение длительного времени, вы рискуете генерировать исключение concurrency при обновлении устаревшего объекта.
Вызов Clear() в коллекции Updates, Deletes and Inserts не работает.
GetOriginalEntityState() может быть полезен, но он дает только идентификаторы для внешних ключей, а не фактические объекты, поэтому вы остаетесь с отдельным объектом.
Вот статья, в которой объясняется, как отменить изменения из контекста данных: http://graemehill.ca/discard-changes-in-linq-to-sql-datacontext
EDIT: Calling Refresh() отменяет обновления, но не удаляет и не вставляет.
Обновление будет работать, однако вы должны указать объекты, которые хотите reset.
Например
dataContext.Refresh(RefreshMode.OverwriteCurrentValues, someObject);
Вы можете использовать GetOriginalEntityState (..), чтобы получить исходные значения для объектов, например. Клиенты используют старые кешированные значения.
Вы также можете перебирать изменения, например. обновляет и обновляет только определенные объекты, а не целые таблицы, потому что ограничение производительности будет высоким.
foreach (Customer c in MyDBContext.GetChangeSet().Updates)
{
MyDBContext.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, c);
}
это приведет к отмене изменений с использованием сохраненных данных в базе данных.
Другим решением является сброс используемого datacontext, используя Dispose().
В любом случае хорошей практикой является переопределение методов Insert и Remove в коллекции, например. Клиенты, которых вы используете и добавляете, например. вызов InsertOnSubmit(). Это решит вашу проблему с ожидающими вводами и удалениями.
Отлично напишите на здесь, но вот копия и вставка используемого кода.
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
Мое приложение - это стиль внешнего вида со значком, чтобы выбрать активную форму (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
}
}
Вот как я это сделал. Я просто следовал примеру Тедди выше и упростил его. У меня есть один вопрос, хотя, зачем даже беспокоиться об обновлении на 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;
}