Как мне обработать эту ошибку оптимистического параллелизма в этом коде Entity Framework? - PullRequest
2 голосов
/ 31 марта 2010

У меня есть следующий псевдо-код в некоторых репозиториях проекта, который использует EF4 .

public void Delete(int someId)
{
   // 1. Load the entity for that Id. If there is none, then null.
   // 2. If entity != null, then DeleteObject(..);
}

Довольно просто, но я получаю ошибку во время выполнения: -

ConcurrencyException: магазин, обновление, Оператор вставки или удаления затронул неожиданное количество строк (0).

Теперь вот что происходит: -

  1. В приложении одновременно запущены два экземпляра EF4.
  2. Экземпляр A вызывает удаление.
  3. Вызовы экземпляра B удаляют наносекунду позже.
  4. Экземпляр A загружает объект.
  5. Экземпляр B также загружает объект.
  6. Экземпляр A теперь удаляет эту сущность - классные бананы.
  7. Экземпляр B пытается удалить объект, но его уже нет. Таким образом, no-count или not is 0, когда ожидалось 1 .. или что-то в этом роде. По сути, выяснилось, что элемент, который предполагается удалить, не был удален (потому что это произошло несколько секунд назад).

Я не уверен, что это похоже на условие гонки или что-то в этом роде.

В любом случае, есть ли какие-нибудь трюки, которые я могу здесь сделать, чтобы 2-й звонок не вылетел? Я мог бы превратить это в хранимую процедуру ... но я надеюсь избежать этого прямо сейчас.

Есть идеи? Мне интересно, возможно ли заблокировать эту строку (и только эту строку) при вызове select ... заставляя экземпляр B ждать, пока не будет снята блокировка строки. К этому времени строка удаляется, поэтому, когда Экземпляр B делает свой выбор, данных там нет ... поэтому он никогда не будет удален.

1 Ответ

0 голосов
/ 14 мая 2010

Обычно вы ловите исключение OptimisticConcurrencyException, а затем обрабатываете проблему таким образом, который имеет смысл для вашей бизнес-модели, а затем снова вызываете SaveChanges.

try
{
    myContext.SaveChanges();
}
catch (OptimisticConcurrencyException e)
{
    if (e.StateEntries.FirstOrDefault() is DeletingObject)
        myContext.Detach(e.StateEntries.First();
    myContext.SaveChanges();
}

Дайте этому повод и посмотрите, как вы попали - не протестировано / не скомпилировано или что-то еще - я использовал DeletingObject в качестве типа объекта, который вы пытаетесь удалить. Замените тип вашей сущности.

...