Entity Framework Core: транзакция между чтением и удалением данных - PullRequest
0 голосов
/ 12 сентября 2018

Я столкнулся с проблемой с Entity Framework Core в .NET Core REST API.

Пример модели данных:

Таблица Дом (id, name) ТаблицаКомнаты (id, houseId, name)

В доме может быть несколько комнат, и комната может быть только в одном доме.

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

  Room room = dbContext.Room
    .Include(r => r.House).ThenInclude(h => h.Rooms)
    .Where(r => r.id == id)
    .SingleOrDefaultAsync();

  if (room.House.Rooms.Count > 1) {
    // other rooms are present
    dbContext.Room.Remove(room);
  } else {
    // delete house if it is the last room
    dbContext.House.Remove(room.House);
  }

  dbContext.SaveChanges();

Проблема в том, чтонаш пользовательский интерфейс не удаляет дом за один вызов, он вызывает удаление комнаты для каждой комнаты в доме (и ожидает, что дом будет удален автоматически с последней комнатой).Это вызывает проблему.Вызовы приходят друг за другом, что каждая комната загружает сущность дома, проверяет, является ли она последней, распознает ли другие комнаты, удаляется ли комната, остается ли пустой дом.

Возможно ли это как-то решить (так пустого дома не осталось) например с транзакциями?

Ответы [ 2 ]

0 голосов
/ 12 сентября 2018

Лучшим решением, вероятно, будет создание нового отдельного метода удаления дома, который позаботится обо всем за один вызов.

Если действительно существует какая-то проблема, которая мешает вам выполнить метод DeleteHouse, вы можете решить эту проблему с помощью блокировки. Я думаю, что ваша основная проблема - это состояние гонки. Чтобы решить эту проблему, добавьте блокировку к своему коду удаления номера.

lock(_deleteRoomLock) 
{ \\Your delete room code }

Недостатком этого шаблона является то, что в конечном итоге вы создаете узкое место в коде на стороне сервера при удалении комнат.

Ссылка на документацию по блокировке https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement

0 голосов
/ 12 сентября 2018

Да и нет.Вы можете заключить его в транзакцию - что тривиально.

https://docs.microsoft.com/en-us/ef/core/saving/transactions

показать, как.

Вы просто создаете транзакцию:

использование (var транзакция = context.Database.BeginTransaction ())

В качестве альтернативы вы можете использовать DbTransaction для DbConnection.Та же ссылка.

Но ваш код просто плохо организован.

каждая комната загружает сущность дома, проверяет, является ли она последней, распознает другие комнаты, комната удаляется,пустой дом остается.

Звучит так, будто кто-то абстрагировал БД полностью за некоторыми из этих хороших антипаттернов хранилища - и теперь ЭТО (не транзакция) возвращается, чтобы укусить вас.Вероятно, каждая удаленная комната использует отдельный репозиторий - и бум, транзакции не помогают.

Время рефакторинга.

...