DbContext, обработка исключения параллелизма
Использование EF DbContext. У моего объекта сущности есть столбец версии строки (выпуск SQL Compact версии 4), который используется для проверки параллелизма (ConcurrencyMode = Fixed, StoreGeneratedPattern=Computed).
Чтобы вызвать исключение параллелизма, из пользовательского интерфейса я прочитал одну и ту же запись таблицы в 2 разных формах, отредактировал каждую из них и сохранил одну за другой. Следующий код выполняет фактическую операцию сохранения.
При нажатии кнопки сохранения во 2-й форме ошибка параллелизма происходит, как и ожидалось. Тем не менее, исключение все еще сохраняется со второй попытки, после копирования исходных значений из базы данных. Только третья попытка проходит без ошибок. Может кто-нибудь объяснить мне, что может вызвать эту проблему?
try
{
_ctx.SaveChanges(); //first attempt
}
catch (Exception ex)
{
if (ex is DbUpdateConcurrencyException)
{
var exc = ex as DbUpdateConcurrencyException;
foreach (var entry in exc.Entries)
entry.OriginalValues.SetValues(entry.GetDatabaseValues());
try
{
_ctx.SaveChanges(); //second attempt
}
catch (Exception ex2)
{
if (ex2 is DbUpdateConcurrencyException)
{
var exc2 = ex2 as DbUpdateConcurrencyException;
foreach (var entry in exc2.Entries)
entry.OriginalValues.SetValues(entry.GetDatabaseValues());
try
{
_ctx.SaveChanges(); //third attempt
}
catch (Exception ex3)
{
System.Windows.MessageBox.Show(ex3.Message);
}
}
}
}
}
РЕДАКТИРОВАТЬ: я обнаружил, что это происходит, когда я делаю оба обновления через пользовательский интерфейс. Если в приведенном выше коде, перед первой попыткой, я делаю что-то следующее:
var _ctx2 = new MyDbContext();
var myEntity = _ctx2.MyEntities.Where(ent => ent.Id == 2).Single();
myEntity.Name = "My new name";
_ctx2.SaveChanges();
_ctx2.Dispose();
тогда код работает как положено, учитывая, что другой экземпляр myEntity был обновлен через пользовательский интерфейс; т.е. вторая попытка спасет myEntity. И проблема заключается в следующей строке:
foreach (var entry in exc.Entries)
entry.OriginalValues.SetValues(entry.GetDatabaseValues());
потому что при обновлении через пользовательский интерфейс exc.Entries возвращает не сущность, в которой произошла ошибка параллелизма, а его сущность свойства навигации.
В этом случае MyEntity представляет собой древовидную самоссылающуюся сущность, которая имеет два свойства навигации: ParentEntity и Children.
Итак, после первой попытки сохранения в exc.Entries у меня есть ParentEntity (в неизменном состоянии), и только после второй попытки сохранения exc.Entries возвращает фактическую сущность, в которой возникла ошибка параллелизма.
1 ответ
Хорошо, это похоже на ошибку EF. Смотрите следующее:
http://support.microsoft.com/kb/2390624#appliesto
http://social.msdn.microsoft.com/Forums/en/adodotnetentityframework/thread/ce60bf40-cd05-42f6-ab8f-26b048ec83d7