【问题标题】:EF6 Nested TransactionsEF6 嵌套事务
【发布时间】:2016-09-09 19:42:57
【问题描述】:

我有一个命令服务类,它利用工作单元模式,使用各种方法通过实体框架更新数据库(本例中为 SQL Azure)。

命令服务通过对 dbcontext 实例的引用进行实例化,该实例的生命周期由我选择的 DI 框架管理。

一些命令服务类的方法在一个事务中包装了对数据库的多次更新,例如:

public void UpdateStuff(someEntity)
{
    using(var tx = _db.Database.BeginTransaction())
    {
        //Some updates to db
        _db.SaveChanges();
        //Some other updates to db
        _db.SaveChanges();
        tx.Commit();
    }
}

现在,其中一些方法从它们的事务中调用命令类的其他方法,例如:

public void UpdateWithSomeCascadingStuff(someOtherEntity)
{
    using(var tx = _db.Database.BeginTransaction())
    {
        //Some updates to db
        _db.SaveChanges();

        //Some other cascading logic and updates to db
        var relatedEntityToUpdate = _query.GetSomeEntityToUpdate(someOtherEntity);
        UpdateStuff(relatedEntityToUpdate);
        _db.SaveChanges();
        tx.Commit();
    }
}

显然,通过这样做,我为同一个 DbContext 实例嵌套了 EF 事务。

这是否受支持,是否会造成任何麻烦?我可以采取其他方法吗?

更新: 我正在使用 EF6 代码优先

【问题讨论】:

    标签: c# entity-framework entity-framework-6


    【解决方案1】:

    EntityFramework 的 DBContexts 本身实现了 UnitOfWork 和 Repository 模式。

    EF6 中的上下文还会自动将所有提交包装在一个事务中(如果它还不是其中的一部分)。

    所以,不,您不应该在多个工作单元之间共享上下文。他们应该各有各的。

    更新

    如果您尝试在同一个 DbContext 上启动重复事务:

    An unhandled exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll
    
    Additional information: The connection is already in a transaction and cannot participate in another transaction. EntityClient does not support parallel transactions.
    

    所以不,你不能做你要求的。

    【讨论】:

    • 谢谢,但这并不能回答我的问题。
    • EF 隐藏在客户端代码的接口后面(因为我需要能够在不影响客户端代码的情况下轻松切换存储机制),并且还有一些 CQRS 正在进行。因此,我不得不“包装”它的 UOW 实现。如何,为什么和正确性是一个太长的讨论。我知道 EF 在 SaveChanges 之前将指令包装在单个事务中。在我的场景中,我需要将多个 SaveChanges 调用包装在单个事务中。再一次 - 不是在这里为设计辩护 - 我只是想知道我是否可以将 EF6 事务嵌套在另一个内部。
    • 我已经扩展了我的答案。希望这有助于更好地回答您的问题
    • 我刚刚意识到您可以使用 TransactionScope(使用 System.Transaction)解决“问题”。如果您将每个 DbContext 包装在其自己的 using (var ts = new TransactionScope(TransactionScopeOption.RequiresNew)) { }而不是 使用 BeginTransaction() ,则无论在另一个 TS 中,它们都可以完成任务。将选项设置为 Required 会加入现有范围,如果不存在则创建一个新范围。
    • 这是该线程上第二个使“RequiresNew”倒退的帖子。您不能使用“RequiresNew”嵌套​​事务范围。如果没有创建新的环境事务(即已经有一个活动),RequiresNew 将引发错误。使用“必需”,因为它要么创建一个新的,要么使用现有的(如果已经存在)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-19
    • 2014-12-12
    • 2016-09-10
    • 2016-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多