首页 > 解决方案 > 实体框架 - 混合存储过程和实体的回滚

问题描述

我需要调用一些存储过程(数据插入)并将实体值更新到数据库。

我希望这些操作是原子的,所以如果发生错误,它们都会回滚。

在我的代码中,如果我强制异常来观察回滚的行为,我的实体更改正在回滚,但我的存储过程更改不会回滚。

查看工作单元的实现,它只是查看_context.ChangeTracker.Entries()- 我假设完全忽略任何存储过程更改?

当我将工作单元实施更改为使用

new System.Transactions.TransactionScope()

回滚按预期工作。

我应该使用new System.Transactions.TransactionScope()吗?有什么陷阱吗?

代码

...
using (var scope = _unitOfWork.Begin())
{
    try
    {                    
        var outcome = _context.Database.ExecuteSqlCommand("SOME EXEC COMMAND", parameters);        

        throw new Exception("Something happened");

        scope.Commit(); // Never gets called because of Exception                  
    }
    catch (Exception e)
    {
        scope.Rollback();
    }
}

工作单位:

public class UnitOfWork : IUnitOfWork, ITransaction
{
    private readonly DbContext _context;
    private bool _committed;

    public UnitOfWork(DbContext context)
    {
        _context = context;
    }

    public ITransaction Begin()
    {
        _committed = false;
        return this;
    }

    public void Commit()
    {
        _context.SaveChanges();
        _committed = true;
    }

    public void Rollback()
    {
        foreach (var entry in _context.ChangeTracker.Entries())
        {
            switch (entry.State)
            {
                case EntityState.Modified:
                    entry.State = EntityState.Unchanged;
                    break;
                case EntityState.Added:
                    entry.State = EntityState.Detached;
                    break;
                case EntityState.Deleted:
                    entry.Reload();
                    break;
                case EntityState.Detached:
                    break;
                case EntityState.Unchanged:
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
    }

    public void Dispose(bool disposing)
    {
        if (!disposing) 
            return;

        if (!_committed)
        {
            Rollback();
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

标签: c#entity-frameworktransactions

解决方案


是的——当然,更改跟踪器只能跟踪您通过课程更改/修改/添加的任何内容DbContext

运行存储过程超出了 EF Change Tracker 的范围 - 因此,如果您将“回滚”简单地基于 Change Tracker 中的内容,您将无法正确处理存储过程所做的任何事情。

使用TransactionScope是根本不同的 - 这是所有数据库操作的“保护伞” - 包括正在执行的任何存储过程 - 因为它基本上是在数据库级别上。因此,基于事务范围的回滚将回滚所有数据库操作——无论是通过 EF 处理DbContext,还是通过其他方式处理。


推荐阅读