DbContext, обработка исключения параллелизма

Использование EF DbContext. В моем объекте сущности есть столбец rowversion (выпуск SQL Compact версии 4), который используется для проверки параллелизма (ConcurrencyMode = Fixed, StoreGeneratedPattern = Computed).

Чтобы вызвать исключение параллелизма, из пользовательского интерфейса я прочитал одну и ту же запись таблицы в двух разных формах, отредактировал каждую из них и сохранил одну за другой. Следующий код выполняет фактическую операцию сохранения.

При нажатии кнопки сохранения во второй форме возникает ошибка параллелизма, как и ожидалось. Однако исключение по-прежнему сохраняется при второй попытке после копирования исходных значений из базы данных. Только третья попытка удалась без ошибок. Может кто-нибудь объяснить мне, что может вызвать эту проблему?

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 возвращает фактическую сущность, в которой возникла ошибка параллелизма.


person synergetic    schedule 13.12.2012    source источник
comment
Side Note: Вы можете использовать catch(DbUpdateConcurrencyException ex) вместо проверки типа исключения с помощью if.   -  person NaveenBhat    schedule 13.12.2012


Ответы (1)


Хорошо, это похоже на ошибку EF. См. следующее:

http://support.microsoft.com/kb/2390624#appliesto
http://social.msdn.microsoft.com/Forums/en/adodotnetentityframework/thread/ce60bf40-cd05-42f6-ab8f-26b048ec83d7
person synergetic    schedule 15.12.2012