Поделиться через


Сохранение изменений и управление параллелизмом (платформа Entity Framework)

Платформа Entity Framework реализует модель оптимистичного параллелизма. Это означает, что в источнике данных не удерживаются блокировки данных. Однако по умолчанию службы объектов сохраняют изменения объектов в базе данных, не проверяя на параллелизм. Для свойств, которые могут обладать высокой степенью параллелизма, рекомендуется определять свойство сущности на концептуальном уровне с атрибутом ConcurrencyMode="fixed", как показано в следующем примере:

<Property Name="Status" Type="Byte" Nullable="false" ConcurrencyMode="Fixed" />

При использовании этого атрибута службы объектов, прежде чем сохранить изменения, проверяют их в базе данных. Любое конфликтующее изменение вызывает исключение OptimisticConcurrencyException. Дополнительные сведения см. в разделе Как управлять параллелизмом данных в контексте объекта (платформа Entity Framework). Исключение OptimisticConcurrencyException может также возникнуть при определении модели Entity Data Model, которая использует хранимые процедуры для обновления источника данных. В том случае исключение возникает в том случае, когда хранимая процедура, используемая для выполнения обновлений, сообщает о том, что обновлено ноль строк. Дополнительные сведения см. в разделе Поддержка хранимых процедур (платформа Entity Framework).

При выполнении обновлений в таких сценариях с высокой степенью параллелизма рекомендуется регулярно вызывать метод Refresh. При вызове метода Refresh объект RefreshMode управляет распространением изменений. Параметр StoreWins заставит службы объектов перезаписать все данные в кэше объектов соответствующими значениями из базы данных. И наоборот, параметр ClientWins замещает исходные значения в кэше последними значениями из источника данных. Это обеспечивает успешное сохранение в источнике данных всех измененных данных в кэше объектов, устраняя конфликты между изменениями данных в кэше и изменениями тех же данных в источнике данных.

Вызовите метод Refresh после вызова метода SaveChanges, если обновления хранилища данных могут изменить данные, принадлежащие другим объектам в контексте объекта. Например, когда добавляется новый элемент SalesOrderDetail в модели AdventureWorks Sales, триггеры обновляют столбец SubTotal, чтобы отразить значение подытогов с учетом нового элемента. В этом случае вызовите метод Refresh и передайте объект SalesOrderHeader для заказа. Это гарантирует отправку значений, созданных триггерами, обратно объекту SalesOrderHeader в контексте объекта.

Службы объектов отслеживают изменения объектов в кэше. При вызове метода SaveChanges службы объектов пытаются выполнить слияние изменений в источнике данных. Метод SaveChanges может вызвать исключение OptimisticConcurrencyException, если изменения данных в кэше объектов конфликтуют с изменениями в источнике данных, произведенными после добавления или обновления объектов в кэше. Это приводит к откату всей транзакции. При возникновении исключения OptimisticConcurrencyException необходимо обработать его, вызвав метод Refresh и указав способ разрешения конфликта: сохранением данных в данных объекта (ClientWins) или обновлением кэша объекта данными из источника данных (StoreWins), как в следующем примере.

Try
    ' Try to save changes, which may cause a conflict.
    Dim num As Integer = context.SaveChanges()
    Console.WriteLine("No conflicts. " + _
                      num.ToString() + " updates saved.")
Catch ex As OptimisticConcurrencyException
    ' Resolve the concurrency conflict by refreshing the 
    ' object context before re-saving changes. 
    context.Refresh(RefreshMode.ClientWins, orders)

    ' Save changes.
    context.SaveChanges()
    Console.WriteLine("OptimisticConcurrencyException " _
                      + "handled and changes saved.")
End Try
try
{
    // Try to save changes, which may cause a conflict.
    int num = context.SaveChanges();
    Console.WriteLine("No conflicts. " +
        num.ToString() + " updates saved.");
}
catch (OptimisticConcurrencyException)
{
    // Resolve the concurrency conflict by refreshing the 
    // object context before re-saving changes. 
    context.Refresh(RefreshMode.ClientWins, orders);

    // Save changes.
    context.SaveChanges();
    Console.WriteLine("OptimisticConcurrencyException "
    + "handled and changes saved");
}

Метод SaveChanges может создать исключение UpdateException, когда объект, добавленный в ObjectContext, не удается создать в источнике данных. Это может случиться в том случае, если строка с внешним ключом, на которую указывает связь, уже существует. В такой ситуации нельзя обновлять добавленный объект в контексте объекта методом Refresh. Вместо этого повторно загрузите объект, задав значение OverwriteChanges свойству MergeOption.

Дополнительные сведения об управлении контекстом объекта см. в разделе Как управлять параллелизмом данных в контексте объекта (платформа Entity Framework).

Кроме того, службы объектов принимают во внимание транзакции, определенные в пространстве имен System.Transactions. Дополнительные сведения см. в разделе Управление транзакциями в службах объектов (платформа Entity Framework).

См. также

Основные понятия

Добавление, изменение и удаление объектов (платформа Entity Framework)

Другие ресурсы

Работа с объектами (платформа Entity Framework)