微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 foreach 循环内回滚或提交事务

如何解决在 foreach 循环内回滚或提交事务

我在 MVC 应用程序中使用 Entity Framework 6 和 .Net Framework 4.8。我正在尝试对实体列表(发票)做两件事:

邮件发送失败时,我想回滚我对实体所做的所有更改。

这是我的代码

foreach (var id in listofIds)
{
  using (var dbContextTransaction = db.Database.BeginTransaction())
  {
    try 
    {
      var invoice = db.Invoices.Find(id);
      MakeChangesToInvoice(invoice);
      var pdf = GeneratePdf(invoice);
      SendEmail(pdf);
      db.SaveChanges();
      dbContextTransaction.Commit();
    }
    catch(SomeEmailException)
    {
      dbContextTransaction.Rollback();
    }
  }
}

这里的问题是,当我在错误迭代之后进行成功迭代时,错误迭代的更改(称为回滚)仍然会被保存。

解决方法

您修改的实体仍由上下文跟踪,因此更改将在下一次 SaveChanges 调用(在下一次迭代中)传播到数据库,因此您需要重新创建您的 dbcontext(这可能对性能有显着影响,需要检查)每次迭代或分离实体。像这样:

Invoice invoice = null;
try 
{
  invoice = db.Invoices.Find(id);
  MakeChangesToInvoice(invoice);
  var pdf = GeneratePdf(invoice);
  SendEmail(pdf);
  db.SaveChanges();
  dbContextTransaction.Commit();
}
catch(SomeEmailException)
{
  dbContextTransaction.Rollback();
  // note that if you have complex object graph this possibly will not detach child objects 
  if(invoice != null) dbContext.Entry(invoice).State = EntityState.Detached;
}

或者在合适的情况下使用 this answer 中的 DetachAll。另请注意,如果有两个对象,重新创建上下文可能是更好的选择(或者您只能在上次运行出错的情况下重新创建它)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。