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
Другие вопросы по тегам