Как я могу отклонить все изменения в Linq для DataContext SQL? - PullRequest
44 голосов
/ 03 ноября 2008

В Linq to DataContext SQL я могу вызвать SubmitChanges (), чтобы отправить все изменения.

Я хочу как-то отклонить все изменения в тексте данных и откатить все изменения (предпочтительно без обращения к базе данных).

Возможно ли это?

Ответы [ 10 ]

30 голосов
/ 03 ноября 2008

Почему бы не отбросить контекст данных и просто заменить его новым экземпляром?

18 голосов
/ 26 сентября 2013
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 - отменить ожидающие изменения

10 голосов
/ 06 августа 2009

В .net 3.0 используйте db.GetChangeSet().Updates.Clear() для обновления, db.GetChangeSet().Inserts.Clear() для нового или db.GetChangeSet().Deletes.Clear() для удаленных элементов.

В .net 3.5 и выше результат GetChangeSet () теперь доступен только для чтения, зацикливает коллекцию в for или foreach и обновляет каждую таблицу ChangeSet, как это делали и macias, написанные в его комментарии.

9 голосов
/ 26 января 2010

Вызов Clear () для коллекции Updates, Deletes and Inserts не работает.

GetOriginalEntityState () может быть полезен, но он дает только идентификаторы для связей с внешним ключом, а не фактические сущности, поэтому у вас остается отсоединенный объект.

Вот статья, которая объясняет, как отменить изменения из контекста данных: http://graemehill.ca/discard-changes-in-linq-to-sql-datacontext

РЕДАКТИРОВАТЬ: вызов Refresh () отменяет обновления, но не удаляет и вставляет.

9 голосов
/ 06 ноября 2008

Как сказал Haacked, просто отбросьте контекст данных.

Вы, вероятно, не должны поддерживать контекст данных в течение длительного времени. Они предназначены для транзакционного использования (т. Е. Один контекст данных на элементарный рабочий блок). Если вы сохраняете контекст данных долгое время, вы рискуете создать исключение параллелизма при обновлении устаревшей сущности.

4 голосов
/ 03 ноября 2008

Обновление будет работать, однако вы должны указать сущности, которые хотите сбросить.

Например

dataContext.Refresh(RefreshMode.OverwriteCurrentValues, someObject);
3 голосов
/ 26 января 2010

Вы можете использовать GetOriginalEntityState (..) , чтобы получить исходные значения для объектов, например. Клиенты, использующие старые кэшированные значения.

Вы также можете перебирать изменения, например, обновляет и обновляет только определенные объекты, а не целые таблицы, поскольку снижение производительности будет высоким.

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

это вернет изменения с использованием постоянных данных в базе данных.

Другое решение - сбросить использованный текст данных с помощью Dispose ().

В любом случае хорошей практикой является переопределение методов вставки и удаления в коллекции, например. Клиенты, которых вы используете и добавляете, например, вызов InsertOnSubmit (). Это решит вашу проблему с ожидающими вставками и удалениями.

1 голос
/ 06 декабря 2013

Мое приложение в стиле 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
    }
}
1 голос
/ 25 октября 2012

Отлично, пишите на здесь , но здесь есть копия и вставка используемого кода.

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
0 голосов
/ 15 сентября 2016

Вот как я это сделал. Я просто последовал примеру Тедди выше и упростил его. У меня есть один вопрос, хотя, зачем вообще возиться с обновлением на 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;
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...