Подтвердить что ты не робот

Как я могу отклонить все изменения в Linq в SQL DataContext?

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

Ответ 3

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 - отмените ожидающие изменения

Ответ 4

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

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

Ответ 5

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

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

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

EDIT: Calling Refresh() отменяет обновления, но не удаляет и не вставляет.

Ответ 6

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

Например

dataContext.Refresh(RefreshMode.OverwriteCurrentValues, someObject);

Ответ 7

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

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

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

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

Другим решением является сброс используемого datacontext, используя Dispose().

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

Ответ 8

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

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

Ответ 9

Мое приложение - это стиль внешнего вида со значком, чтобы выбрать активную форму (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
    }
}

Ответ 10

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