c# - EF6 中的嵌套事务行为

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

我目前正在使用 TransactionScope 来管理我的数据层中的事务,但我一直遇到嵌套事务和异步问题,据此连接似乎在嵌套事务期间关闭或事务被提升到 MSDTC。我还没有找到确切的问题,但在阅读之后看起来这个场景不是 particuarly well支持,我应该改用 Database.BeginTransaction()。

我的问题是我找不到有关 Database.BeginTransaction() 如何处理嵌套事务的信息,特别是在我想要使用环境事务而不是创建新事务的情况下。我怀疑它不打算以这种方式工作,如果我想管理嵌套事务,我应该抽象出事务管理以给我更多的控制权。

不想添加不必要的抽象层我想知道是否有人在这方面有经验并且可以确认嵌套在另一个事务中时 Database.BeginTransaction() 的行为?

有关我的 DAL 的其他信息:基于 CQS 模式,我倾向于将与 Db 相关的代码封装在命令或查询处理程序中,因此一个简化/设计的嵌套示例如下:

public class AddBlogPostHandler
{
    private readonly MyDbContext _myDbContext;

    public AddBlogPostHandler(MyDbContext myDbContext)
    {
        _myDbContext = myDbContext;
    }

    public async Task ExecuteAsync(AddBlogPostCommand command)
    {
        using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
        {
            // .. code to create and add a draft blog post to the context
            await _myDbContext.SaveChangesAsync();

            var publishBlogPostCommand = new PublishBlogPostCommand();
            // ..set some variables on the PublishBlogPostCommand
            await PublishBlogPostAsync(command);

            scope.Complete();
        }
    }
}

public class PublishBlogPostHandler
{
    private readonly MyDbContext _myDbContext;

    public PublishBlogPostHandler(MyDbContext myDbContext)
    {
        _myDbContext = myDbContext;
    }

    public async Task ExecuteAsync(PublishBlogPostCommand command)
    {
        using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
        {
            // .. some code to do one set of update
            await _myDbContext.SaveChangesAsync();

            // .. some other db updates that need to be run separately
            await _myDbContext.SaveChangesAsync();

            scope.Complete();
        }
    }
}

最佳答案

在内部事务可以独立提交或回滚的意义上,不存在嵌套事务。嵌套事务实际上只维护一个引用计数。在最后一次提交时,我们得到了物理提交。在第一次回滚时,我们得到一个物理回滚。只需确保您了解这一点即可。

避免使用 MSDTC 很重要。这对于 TransactionScopeBeginTransaction 都是可能的。对于前者,您需要显式打开范围内的连接,以便 EF 不会一直打开新连接。

正如您在问题中所读到的,这是 EF 中的一个缺陷(L2S 没有)。请花时间对问题发表评论,以确保团队知道客户遇到了这个问题。

particularly in my scenario where i'm wanting to use the ambient transaction rather than create a new one.

这非常适合 TransactionScope。我认为您切换到 BeginTransaction 是基于误解。也许你可以在评论中澄清。

confirm the behavior of Database.BeginTransaction() when nested inside another transaction

在第一段中解释。

Additional information about my DAL: Based on CQS pattern, I tend to encapsulate Db related code in command or query handlers, so a simplified/contrived example of how this nesting occurs would be:

代码看起来不错,除了缺少 db.Connection.Open() 调用(如上所述)。

此模式将支持在同一事务中执行多个查询和命令。只需将另一个范围包裹在它周围。确保不要打开连接两次,例如在采取行动之前检查 conn.State

关于c# - EF6 中的嵌套事务行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34159752/

相关文章:

c# - ASP.Net C# 变量不存储在网页上

c# - 如何在应用程序打开时更改应用程序设置(设置)?

entity-framework - 如何在代码中从 EDMX 模型获取字符串的最大长度?

transactions - 智能合约和交易有什么区别?

php - 多种功能的交易

c# - 动画 : Sliding & Fading controls on a C# form (winforms)

c# - 如何在不创建安装程序的情况下安装 C# Windows 服务?

asp.net - 如何批量更新用户的安全印章? Asp.net 身份

c# - 使用 foreach() 从集合中删除多个实体?

transactions - TypeORM 事务保存实体到数据库,尽管下一个事务步骤失败