Фиксация транзакции в цикле foreach - PullRequest
0 голосов
/ 27 мая 2020

Я добавляю запись в БД в foreach l oop и использую транзакции. Но я получаю эту ошибку:

The connection is already in a transaction and cannot participate in another transaction.

ОБНОВЛЕНИЕ :

        var user = await CurrentUser;

        if (user.IsNotNull())
        {
                using (var transaction = _context.Database.BeginTransaction())
                {
                    try
                    {
                        var reports = new List<ReportEntity>();

                        foreach (var model in modelList)
                        {
                            reports.Add(new ReportEntity
                            {
                                Id = Guid.NewGuid(),
                                UserId = user.Id,,
                                ReportTypeId =  ReportTypeId
                            });
                        }

                        await _context.tbl_Reports.AddRangeAsync(reports);
                        await _context.SaveChangesAsync();
                        await transaction.CommitAsync();
                        resp.Status = true;
                    }
                    catch (Exception e)
                    {
                        resp.ErrorMessage = e.Message;
                        await transaction.RollbackAsync();
                    }
                } //End of transaction
            }
         }
        else
        {
            resp.ErrorMessage = "User not found";
        }

Я добавляю записи в al oop в зависимости от массива объектов в POST. Когда я должен зафиксировать транзакцию, чтобы не получить эту ошибку?

1 Ответ

1 голос
/ 27 мая 2020

Похоже, вы не закрываете транзакцию, если user равно нулю. Вот что на самом деле происходит в вашем коде:

  1. вы вызываете метод, который вызывает _context.Database.BeginTransaction()
  2. транзакция открывается для соединения
  3. user имеет значение null , что приводит к тому, что не вызывается CommitAsync или RollbackAsync
  4. транзакция все еще используется даже после завершения выполнения метода, она открыта в соединении
  5. вы вызываете этот метод снова, возможно при создании нового контекста EF, однако, контекст EF не создает новое соединение каждый раз, он будет повторно использовать существующее из пула соединений
  6. Контекст EF выбирает соединение, которое использовалось на шаге 2, с уже открытым транзакция
  7. вы пытаетесь открыть другую транзакцию в соединении, которое уже открыло транзакцию, и получаете исключение (даже если на этот раз user не равно null)

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

В документации SqlConnection.BeginTransaction говорится:

Вы должны явно зафиксировать или откатить транзакцию с помощью метода Commit или Rollback.

ОБНОВЛЕНИЕ Если упомянутое выше не помогло, есть другие вещи, которые следует рассмотреть и проверить:

  • Существуют сторонние библиотеки которые взаимодействуют с базой данных и открытыми транзакциями. Иногда они помогают работать с EF и предоставляют такой функционал, как BatchInsert или BatchUpdate. Их можно было бы вызвать где-нибудь в вашем коде.
  • Одновременный доступ к одному контексту EF, если он хранится, например, в поле stati c и несколько потоков пытаются использовать его одновременно.
  • Внешний код может создать транзакцию до того, как ваш код был вызван, также ваш код может создать транзакцию во вложенных вызовах.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...