Сохранение изменений и управление параллелизмом (платформа 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)