在 foreach 循环中提交事务

Commit transaction in foreach loop

我在 foreach 循环中向 DB 添加一个条目并使用事务。但我收到此错误:

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";
        }

我正在根据 POST 中的对象数组循环添加记录。我什么时候提交交易才不会收到这个错误?

看起来您没有关闭交易以防 user 为空。这是您的代码中实际发生的情况:

  1. 你调用了调用_context.Database.BeginTransaction()的方法
  2. 为连接打开一个事务
  3. user为null,导致不调用CommitAsyncRollbackAsync
  4. 即使在方法执行完成后事务仍在使用中,它在连接上打开
  5. 您再次调用该方法,可能会创建一个新的 EF 上下文,但是,EF 上下文不会每次都创建一个新连接,它会重新使用连接池中现有的连接
  6. EF 上下文选择在第 2 步中使用的连接,并且事务已经打开
  7. 您尝试在已打开事务的连接上打开另一个事务,但出现异常(即使这次 user 不为空)

我想应该是这样的。您可以尝试 commit/rollback 事务,即使数据库中没有任何更改,这应该可以解决问题。

关于 SqlConnection.BeginTransaction 的文档说:

You must explicitly commit or roll back the transaction using the Commit or Rollback method.

更新 如果上面提到的没有帮助,还有其他的事情应该考虑和检查:

  • 有第三方库与数据库交互并打开事务。有时他们帮助使用 EF 并提供 BatchInsertBatchUpdate 等功能。它们可以在您的代码中的某处调用。
  • 同时访问单个 EF 上下文,例如,如果它存储在静态字段中并且多个线程试图同时使用它。
  • 外部代码可以在调用您的代码之前创建交易,您的代码也可以在嵌套调用中创建交易。

注意所有用到异常的EF上下文的地方。