ОБНОВЛЕНИЕ (2010-12-21): полностью переписал этот вопрос на основе тестов, которые я проводил. Кроме того, раньше это был специфичный для POCO вопрос, но оказалось, что мой вопрос не обязательно специфичен для POCO.
Я использую Entity Framework, и в моей таблице базы данных есть столбец отметки времени, который следует использовать для отслеживания изменений для оптимистичного параллелизма. Я установил режим параллелизма для этого свойства в Entity Designer на «Fixed», и я получаю противоречивые результаты. Вот несколько упрощенных сценариев, которые демонстрируют, что проверка параллелизма работает в одном сценарии, но не в другом.
Успешно генерирует OptimisticConcurrencyException:
Если я присоединяю отключенную сущность, то SaveChanges генерирует исключение OptimisticConcurrencyException в случае конфликта меток времени:
[HttpPost]
public ActionResult Index(Person person) {
_context.People.Attach(person);
var state = _context.ObjectStateManager.GetObjectStateEntry(person);
state.ChangeState(System.Data.EntityState.Modified);
_context.SaveChanges();
return RedirectToAction("Index");
}
Не создает исключение OptimisticConcurrencyException:
С другой стороны, если я получаю новую копию своей сущности из базы данных и выполняю частичное обновление некоторых полей, а затем вызываю SaveChanges (), то, несмотря на конфликт меток времени, я не получить исключение OptimisticConcurrencyException:
[HttpPost]
public ActionResult Index(Person person) {
var currentPerson = _context.People.Where(x => x.Id == person.Id).First();
currentPerson.Name = person.Name;
// currentPerson.VerColm == [0,0,0,0,0,0,15,167]
// person.VerColm == [0,0,0,0,0,0,15,166]
currentPerson.VerColm = person.VerColm;
// in POCO, currentPerson.VerColm == [0,0,0,0,0,0,15,166]
// in non-POCO, currentPerson.VerColm doesn't change and is still [0,0,0,0,0,0,15,167]
_context.SaveChanges();
return RedirectToAction("Index");
}
Основываясь на SQL Profiler, похоже, что Entity Framework игнорирует новый VerColm (который является свойством временной метки) и вместо этого использует первоначально загруженный VerColm. Из-за этого он никогда не вызовет исключение OptimisticConcurrencyException.
ОБНОВЛЕНИЕ: Добавление дополнительной информации по запросу Яна:
Обратите внимание, что я также добавил комментарии к приведенному выше коду, чтобы они совпадали с тем, что я вижу в своем действии контроллера при работе с этим примером.
Это значение VerColm в моей базе данных до обновления: 0x0000000000000FA7
Вот что показывает SQL Profiler при обновлении:
exec sp_executesql N'update [dbo].[People]
set [Name] = @0
where (([Id] = @1) and ([VerColm] = @2))
select [VerColm]
from [dbo].[People]
where @@ROWCOUNT > 0 and [Id] = @1',N'@0 nvarchar(50),@1 int,@2 binary(8)',@0=N'hello',@1=1,@2=0x0000000000000FA7
Обратите внимание, что @ 2 должно быть 0x0000000000000FA6, но это 0x0000000000000FA7
Вот VerColm в моей базе данных после обновления: 0x0000000000000FA8
Кто-нибудь знает, как я могу обойти эту проблему? Я хотел бы, чтобы Entity Framework выдавал исключение при обновлении существующей сущности и конфликте меток времени.
Спасибо