UPDATE (2010-12-21): Полностью переписал этот вопрос на основе тестов, которые я делал. Кроме того, это был конкретный вопрос POCO, но, оказывается, мой вопрос не обязательно специфичен для POCO.
Я использую Entity Framework, и у меня есть столбец timestamp в моей таблице базы данных, который должен использоваться для отслеживания изменений для оптимистического concurrency. Я установил режим concurrency для этого свойства в Entity Designer на "Fixed", и я получаю противоречивые результаты. Вот несколько упрощенных сценариев, которые демонстрируют, что проверка concurrency работает в одном сценарии, но не в другом.
Успешно выбрасывает исключение 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 (который является свойством timestamp) и вместо этого использует первоначально загруженный 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 выдавал исключение, когда я обновляю существующий объект и там конфликтует временная метка.
Спасибо