在实体框架事务中出现异常时回滚不还原子实体记录

Rollback not restoring child entity records during exception in Entity Framework transaction

提问人:Bakri Alloush 提问时间:8/3/2023 最后编辑:Bakri Alloush 更新时间:8/4/2023 访问量:43

问:

问题:

我在实体框架事务中遇到了回滚行为的问题。我有一个场景,我要删除事务中的父实体及其子实体。但是,如果在提交事务之前发生异常,则回滚会成功还原父实体,但子实体记录仍会被删除。

下面是简化的代码结构:

付款控制器.cs

try
{
  uow.BeginTransaction();
  var moneyTransaction = uow.MoneyTransactions.GetById(id);
  var log = new LogRecord(LogRecordType.Delete)
  {
    TransId = moneyTransaction.Id,
    TransType = moneyTransaction.Type,
    Data1 = moneyTransaction.Splits[0].Account.ToString(),
    Data2 = moneyTransaction.Splits[1].Account.ToString(),
    Notes = moneyTransaction.Notes,
  };
  uow.LogRecords.Add(log);
  uow.MoneyTransactions.Delete(id);
  deleted = uow.Save();
}
catch (Exception ex)
{
    uow.Rollback();
    throw ex;
}

UoW.cs

public bool Save()
{
    var saved = _context.SaveChanges();
    transaction.Commit();
    return saved > 0;
}

public void BeginTransaction()
{
    transaction = _context.Database.BeginTransaction();
}

public void Rollback()
{
    transaction.Rollback();
}

问题在于,在回滚期间不会还原 Splits 子实体记录,而在引发异常时会成功还原父实体 MoneyTransaction。

如何确保在事务范围内发生异常时,子实体记录(拆分)也回滚?有没有更好的方法来有效地处理这些情况?

我的尝试:

  1. 删除行 {{ uow.LogRecords.Add(日志);}} 修复了回滚行为
  2. 没有伍伦贡工作并不能解决问题。

编辑:

我在BbContext类中有以下代码:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Transaction>()
                .HasMany(t => t.Splits)
                .WithRequired(s => s.Transaction)
                .HasForeignKey(s => s.Transaction_Id)
                .WillCascadeOnDelete(true);

            modelBuilder.Entity<Transaction>()
                .Property(t => t.RowVersion)
                .IsRowVersion();

            base.OnModelCreating(modelBuilder);
        }
    }
C# 实体框架 并发 回滚

评论


答:

1赞 Bakri Alloush 8/4/2023 #1

我通过分别初始化每个表单中的 DbContext 实例来解决此问题,因为以前我仅在 Program.cs 文件中初始化它并将其传递给所有程序,如下所示:

using (DBContext cxt = new DBContext())
{
    Application.Run(new FormLogin(cxt));
}

现在变成这样:

程序.cs

Application.Run(new FormLogin());

表单登录.cs

public FormLogin()
{
    cxt = new DBContext();
}