fix(transaction): preserve primary failures
Keep action and commit exceptions when rollback fails; clear owned transaction state and cover the lifecycle with SQLite tests. Ref: IT-1588
This commit is contained in:
@@ -27,71 +27,60 @@ public class EfUnitOfWork<TDbContext> : IUnitOfWork
|
||||
return _currentTransaction;
|
||||
}
|
||||
|
||||
public async Task ExecuteInTransactionAsync(Func<Task> action)
|
||||
public Task ExecuteInTransactionAsync(Func<Task> action)
|
||||
{
|
||||
ITransaction? existing = GetCurrentTransaction();
|
||||
bool ownsTransaction = existing is null;
|
||||
|
||||
ITransaction tx = existing ?? await BeginTransactionAsync();
|
||||
|
||||
try
|
||||
return ExecuteInTransactionAsync(async () =>
|
||||
{
|
||||
await action();
|
||||
if (ownsTransaction)
|
||||
{
|
||||
await tx.CommitAsync();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (ownsTransaction)
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (ownsTransaction)
|
||||
{
|
||||
await tx.DisposeAsync();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<TResult> ExecuteInTransactionAsync<TResult>(Func<Task<TResult>> action)
|
||||
{
|
||||
ITransaction? existing = GetCurrentTransaction();
|
||||
bool ownsTransaction = existing is null;
|
||||
if (existing is not null)
|
||||
{
|
||||
return await action();
|
||||
}
|
||||
|
||||
ITransaction tx = existing ?? await BeginTransactionAsync();
|
||||
ITransaction tx = await BeginTransactionAsync();
|
||||
|
||||
try
|
||||
{
|
||||
TResult result = await action();
|
||||
if (ownsTransaction)
|
||||
{
|
||||
await tx.CommitAsync();
|
||||
}
|
||||
await tx.CommitAsync();
|
||||
|
||||
return result;
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (ownsTransaction)
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
}
|
||||
|
||||
await TryRollbackAsync(tx);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (ownsTransaction)
|
||||
try
|
||||
{
|
||||
await tx.DisposeAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_currentTransaction = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task TryRollbackAsync(ITransaction transaction)
|
||||
{
|
||||
try
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Rollback can fail when the provider has already completed the transaction.
|
||||
// Preserve the action or commit exception that caused the rollback attempt.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user