假设我有以下 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/