c# - 如何在工作单元 TransactionScope 内启用RetryOnFailure?

标签 c# entity-framework-core transactionscope

假设我有以下 UnitOfWork,它可以注入(inject)到处理程序中并用于在 TransactionScope 内执行数据库操作:

internal sealed class UnitOfWork : IUnitOfWork
{
    private readonly TransactionScope _transactionScope;

    public UnitOfWork(IOptions<UnitOfWorkOptions> options)
    {
        EnsureArg.IsNotNull(options, nameof(options));

        _transactionScope = new TransactionScope(
            TransactionScopeOption.RequiresNew,
            new TransactionOptions
            {
                IsolationLevel = IsolationLevel.ReadCommitted,
                Timeout = TransactionManager.DefaultTimeout,
            },
            TransactionScopeAsyncFlowOption.Enabled);
    }

    Task CompleteAsync(CancellationToken cancellationToken)
    {
        _transactionScope.Complete();
        Dispose(true);
        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
        => Dispose(true);

    private void Dispose(bool disposing)
    {
        _transactionScope.Dispose();
    }
}

在我的处理程序中:

public MyHandler(IUnitOfWork unitOfWork, IRepository repository)
{
    _unitOfWork = unitOfWork;
    _repository = repository;
}

public async Task HandleAsync(CancellationToken cancellationToken)
{
    var entity = await _repository.GetItem(cancellationToken);
    await _unitOfWork.CompleteAsync(cancellationToken);
}

启用 ef core 的 connection resilience 后使用 EnableRetryOnFailure 每当我的工作单元内发生任何事务时,我都会收到这个恼人的错误:

System.InvalidOperationException: 'The configured execution strategy 'SqlServerRetryingExecutionStrategy' does not support user-initiated transactions. Use the execution strategy returned by 'DbContext.Database.CreateExecutionStrategy()' to execute all the operations in the transaction as a retriable unit.'

因此,我注入(inject)了 DbContext 并尝试将我的数据库代码传递到 CompleteAsync 中以将其包装在执行策略中,但同样的错误仍然存​​在:

Task CompleteAsync(Func<Task> action, CancellationToken cancellationToken)
{
    var strategy = _dbContext.Database.CreateExecutionStrategy();
    return strategy.ExecuteAsync(
        async () =>
        {
            await action();
            _transactionScope.Complete();
            Dispose(true); 
            return Task.CompletedTask;
        });
}

处理程序:

public async Task HandleAsync(CancellationToken cancellationToken)
{
    var task = new Func<Task>(async () =>
    {
        var entity = await _repository.GetItem(cancellationToken);
    });
    await _unitOfWork.CompleteAsync(task, cancellationToken);
}

我还尝试简单地将 _transactionScope.Complete(); 包装在执行策略中,但不出所料,它没有帮助

有人知道如何实现这个目标吗?

最佳答案

我是这样工作的

Task CompleteAsync(Func<Task> action, CancellationToken cancellationToken)
{
    var strategy = _dbContext.Database.CreateExecutionStrategy();
    return strategy.ExecuteAsync(
        async () =>
        {
            using (var transaction = new TransactionScope())
            {
                await action();
                transaction.Complete();
                Dispose(true); 
                return Task.CompletedTask;
            }
        });
}

因此,它不是在构造函数中初始化 TransactionScope,而是在最后一刻创建,并包含在执行策略中

他们确实在 the docs 中这样做了:

using (var context1 = new BloggingContext())
{
    context1.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/visualstudio" });

    var strategy = context1.Database.CreateExecutionStrategy();

    strategy.Execute(
        () =>
        {
            using (var context2 = new BloggingContext())
            {
                using (var transaction = new TransactionScope())
                {
                    context2.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
                    context2.SaveChanges();

                    context1.SaveChanges();

                    transaction.Complete();
                }
            }
        });
}

关于c# - 如何在工作单元 TransactionScope 内启用RetryOnFailure?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70944354/

相关文章:

c# - TransactionScope 中的所有代码如何在范围提交或回滚之前不会真正执行?

c# - 无法加载文件或程序集 Windows.winmd'

c# - 在 EF Core 7.0 中使用 Database.SqlQuery<T> 查询自定义类型

c# - 如何知道代码是否在 TransactionScope 内?

c# - Serializable transactions 是否只锁定其他 transactionscope 语句?还是一切?

c# - Linq 请求对数据库进行大量查询

c# - 在 C# 中将二维数组转换为一维数组?

c# - 动画 RenderTransformOrigin

c# - 无法找到 testhost.dll。请发布您的测试项目并重试。 (.Net 核心 2.1)

c# - 在 Entity Framework Core 中使用两列的一对多关系