2024-06-23 18:15:32 -04:00
|
|
|
|
using System.Data.Common;
|
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
using Dapper;
|
|
|
|
|
using FruityFoundation.DataAccess.Abstractions;
|
|
|
|
|
|
2024-06-23 22:27:05 -04:00
|
|
|
|
namespace FruityFoundation.DataAccess.Core;
|
2024-06-23 18:15:32 -04:00
|
|
|
|
|
2024-06-23 22:27:05 -04:00
|
|
|
|
// ReSharper disable once ClassWithVirtualMembersNeverInherited.Global
|
2024-06-23 18:15:32 -04:00
|
|
|
|
public class DbTransaction<TConnectionType> : IDatabaseTransactionConnection<TConnectionType>
|
|
|
|
|
where TConnectionType : ConnectionType
|
|
|
|
|
{
|
2024-06-23 22:27:05 -04:00
|
|
|
|
private readonly DbTransaction _transaction;
|
2024-06-23 18:15:32 -04:00
|
|
|
|
|
2024-06-23 22:27:05 -04:00
|
|
|
|
internal DbTransaction(DbTransaction transaction)
|
2024-06-23 18:15:32 -04:00
|
|
|
|
{
|
|
|
|
|
_transaction = transaction;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public async Task<IEnumerable<T>> Query<T>(
|
|
|
|
|
string sql,
|
|
|
|
|
object? param = null,
|
|
|
|
|
CancellationToken cancellationToken = default
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
if (_transaction.Connection is not { } conn)
|
|
|
|
|
throw new InvalidOperationException("Transaction connection cannot be null");
|
|
|
|
|
|
|
|
|
|
var command = new CommandDefinition(sql, param, transaction: _transaction, cancellationToken: cancellationToken);
|
|
|
|
|
|
|
|
|
|
return await conn.QueryAsync<T>(command);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public async IAsyncEnumerable<T> QueryUnbuffered<T>(
|
|
|
|
|
string sql,
|
|
|
|
|
object? param = null,
|
|
|
|
|
[EnumeratorCancellation] CancellationToken cancellationToken = default
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
if (_transaction.Connection is not { } conn)
|
|
|
|
|
throw new InvalidOperationException("Transaction connection cannot be null");
|
|
|
|
|
|
|
|
|
|
var query = conn.QueryUnbufferedAsync<T>(sql, param, transaction: _transaction)
|
|
|
|
|
.WithCancellation(cancellationToken);
|
|
|
|
|
|
|
|
|
|
await foreach (var item in query)
|
|
|
|
|
yield return item;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public async Task<T> QuerySingle<T>(string sql, object? param = null, CancellationToken cancellationToken = default)
|
|
|
|
|
{
|
|
|
|
|
if (_transaction.Connection is not { } conn)
|
|
|
|
|
throw new InvalidOperationException("Transaction connection cannot be null");
|
|
|
|
|
|
|
|
|
|
var command = new CommandDefinition(sql, param, transaction: _transaction, cancellationToken: cancellationToken);
|
|
|
|
|
|
|
|
|
|
return await conn.QuerySingleAsync<T>(command);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public async Task Execute(string sql, object? param = null, CancellationToken cancellationToken = default)
|
|
|
|
|
{
|
|
|
|
|
if (_transaction.Connection is not { } conn)
|
|
|
|
|
throw new InvalidOperationException("Transaction connection cannot be null");
|
|
|
|
|
|
|
|
|
|
var command = new CommandDefinition(sql, param, transaction: _transaction, cancellationToken: cancellationToken);
|
|
|
|
|
|
|
|
|
|
await conn.ExecuteAsync(command);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public async Task<T?> ExecuteScalar<T>(string sql, object? param = null, CancellationToken cancellationToken = default)
|
|
|
|
|
{
|
|
|
|
|
if (_transaction.Connection is not { } conn)
|
|
|
|
|
throw new InvalidOperationException("Transaction connection cannot be null");
|
|
|
|
|
|
|
|
|
|
var command = new CommandDefinition(sql, param, transaction: _transaction, cancellationToken: cancellationToken);
|
|
|
|
|
|
|
|
|
|
return await conn.ExecuteScalarAsync<T>(command);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public async Task<DbDataReader> ExecuteReader(
|
|
|
|
|
string sql,
|
|
|
|
|
object? param = null,
|
|
|
|
|
CancellationToken cancellationToken = default
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
if (_transaction.Connection is not { } conn)
|
|
|
|
|
throw new InvalidOperationException("Transaction connection cannot be null");
|
|
|
|
|
|
|
|
|
|
var command = new CommandDefinition(sql, param, transaction: _transaction, cancellationToken: cancellationToken);
|
|
|
|
|
|
|
|
|
|
return await conn.ExecuteReaderAsync(command);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public async Task Commit(CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
await _transaction.CommitAsync(cancellationToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public async Task Rollback(CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
await _transaction.RollbackAsync(cancellationToken);
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-23 22:27:05 -04:00
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
|
|
|
{
|
|
|
|
|
if (disposing)
|
|
|
|
|
{
|
|
|
|
|
#pragma warning disable IDISP007
|
|
|
|
|
_transaction.Dispose();
|
|
|
|
|
#pragma warning restore IDISP007
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-23 18:15:32 -04:00
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
2024-06-23 22:27:05 -04:00
|
|
|
|
Dispose(true);
|
2024-06-23 18:15:32 -04:00
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-23 22:27:05 -04:00
|
|
|
|
protected virtual async ValueTask DisposeAsyncCore()
|
|
|
|
|
{
|
|
|
|
|
#pragma warning disable IDISP007
|
|
|
|
|
await _transaction.DisposeAsync();
|
|
|
|
|
#pragma warning restore IDISP007
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-23 18:15:32 -04:00
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public async ValueTask DisposeAsync()
|
|
|
|
|
{
|
2024-06-23 22:27:05 -04:00
|
|
|
|
await DisposeAsyncCore();
|
2024-06-23 18:15:32 -04:00
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
}
|
|
|
|
|
}
|