refactor: Vereinfachung der SQLExecutor-Implementierung zur Rückgabe von IQueryExecutor

- Aktualisiert `SQLExecutor<T>` um `ISQLExecutor<T>` zu implementieren und `IQueryExecutor<T>` für die weitere Abfrageausführung zurückzugeben.
- Umstrukturierte Methoden zur Verwendung von `ToExecutor()` für die Konvertierung von rohen SQL-Abfragen in einen `IQueryExecutor<T>`.
- Geänderter Konstruktor, um `IServiceProvider` für die Injektion von Abhängigkeiten von benutzerdefinierten SQL-Abfrageklassen zu akzeptieren.
This commit is contained in:
Developer 02 2025-04-29 17:14:38 +02:00
parent 6e82b24578
commit 1e54b775a2
4 changed files with 50 additions and 70 deletions

View File

@ -1,41 +1,27 @@
namespace EnvelopeGenerator.Application.Contracts.SQLExecutor;
/// <summary>
/// Defines methods for executing raw SQL queries and mapping the results to <typeparamref name="TEntity"/> objects.
/// Defines methods for executing raw SQL queries or custom SQL query classes and returning query executors for further operations.
/// Provides abstraction for raw SQL execution as well as mapping the results to <typeparamref name="TEntity"/> objects.
/// </summary>
/// <typeparam name="TEntity">The entity type to which the SQL query results will be mapped.</typeparam>
public interface ISQLExecutor<TEntity>
{
/// <summary>
/// Executes a raw SQL query and returns the first result or <c>null</c> if no result is found.
/// Executes a raw SQL query and returns an <see cref="IQueryExecutor{TEntity}"/> for further querying operations on the result.
/// </summary>
/// <param name="sql">The raw SQL query to execute.</param>
/// <param name="cancellation">Optional cancellation token.</param>
/// <param name="cancellation">Optional cancellation token for the operation.</param>
/// <param name="parameters">Optional parameters for the SQL query.</param>
/// <returns>The first <typeparamref name="TEntity"/> result, or <c>null</c> if none found.</returns>
Task<TEntity?> ExecuteFirstAsync(string sql, CancellationToken cancellation = default, params object[] parameters);
/// <returns>An <see cref="IQueryExecutor{TEntity}"/> instance for further query operations on the result.</returns>
IQueryExecutor<TEntity> Execute(string sql, CancellationToken cancellation = default, params object[] parameters);
/// <summary>
/// Executes a raw SQL query and expects a single result, or <c>null</c> if no result is found.
/// Executes a custom SQL query defined by a class that implements <see cref="ISQL{TEntity}"/> and returns an <see cref="IQueryExecutor{TEntity}"/> for further querying operations on the result.
/// </summary>
/// <param name="sql">The raw SQL query to execute.</param>
/// <param name="cancellation">Optional cancellation token.</param>
/// <typeparam name="TSQL">The type of the custom SQL query class implementing <see cref="ISQL{TEntity}"/>.</typeparam>
/// <param name="cancellation">Optional cancellation token for the operation.</param>
/// <param name="parameters">Optional parameters for the SQL query.</param>
/// <returns>The single <typeparamref name="TEntity"/> result, or <c>null</c> if none found.</returns>
Task<TEntity?> ExecuteSingleAsync(string sql, CancellationToken cancellation = default, params object[] parameters);
/// <summary>
/// Executes a raw SQL query and returns all results as a collection of <typeparamref name="TEntity"/>.
/// </summary>
/// <param name="sql">The raw SQL query to execute.</param>
/// <param name="cancellation">Optional cancellation token.</param>
/// <param name="parameters">Optional parameters for the SQL query.</param>
/// <returns>An <see cref="IEnumerable{TEntity}"/> containing all matching results.</returns>
Task<IEnumerable<TEntity>> ExecuteAllAsync(string sql, CancellationToken cancellation = default, params object[] parameters);
Task<TEntity?> ExecuteFirstAsync<TSQL>(CancellationToken cancellation = default, params object[] parameters) where TSQL : ISQL<TEntity>;
Task<TEntity?> ExecuteSingleAsync<TSQL>(CancellationToken cancellation = default, params object[] parameters) where TSQL : ISQL<TEntity>;
Task<IEnumerable<TEntity>> ExecuteAllAsync<TSQL>(CancellationToken cancellation = default, params object[] parameters) where TSQL : ISQL<TEntity>;
/// <returns>An <see cref="IQueryExecutor{TEntity}"/> instance for further query operations on the result.</returns>
IQueryExecutor<TEntity> Execute<TSQL>(CancellationToken cancellation = default, params object[] parameters) where TSQL : ISQL<TEntity>;
}

View File

@ -1,34 +1,42 @@
using EnvelopeGenerator.Application.Contracts.SQLExecutor;
using AngleSharp.Dom;
using EnvelopeGenerator.Application.Contracts.SQLExecutor;
using Microsoft.EntityFrameworkCore;
namespace EnvelopeGenerator.Infrastructure;
public record QueryExecutor<TEntity>(IQueryable<TEntity> Queryable) : IQueryExecutor<TEntity>
public sealed record QueryExecutor<TEntity> : IQueryExecutor<TEntity>
{
public TEntity First() => Queryable.First();
private readonly IQueryable<TEntity> _query;
public Task<TEntity> FirstAsync() => Queryable.FirstAsync();
internal QueryExecutor(IQueryable<TEntity> queryable)
{
_query = queryable;
}
public TEntity? FirstOrDefault() => Queryable.FirstOrDefault();
public TEntity First() => _query.First();
public Task<TEntity> FirstAsync() => _query.FirstAsync();
public TEntity? FirstOrDefault() => _query.FirstOrDefault();
public Task<TEntity?> FirstOrDefaultAsync() => Queryable.FirstOrDefaultAsync();
public Task<TEntity?> FirstOrDefaultAsync() => _query.FirstOrDefaultAsync();
public TEntity Single() => Queryable.Single();
public TEntity Single() => _query.Single();
public Task<TEntity> SingleAsync() => Queryable.SingleAsync();
public Task<TEntity> SingleAsync() => _query.SingleAsync();
public TEntity? SingleOrDefault() => Queryable.SingleOrDefault();
public TEntity? SingleOrDefault() => _query.SingleOrDefault();
public Task<TEntity?> SingleOrDefaultAsync() => Queryable.SingleOrDefaultAsync();
public Task<TEntity?> SingleOrDefaultAsync() => _query.SingleOrDefaultAsync();
public IEnumerable<TEntity> ToList() => Queryable.ToList();
public IEnumerable<TEntity> ToList() => _query.ToList();
public async Task<IEnumerable<TEntity>> ToListAsync() => await Queryable.ToListAsync();
}
public async Task<IEnumerable<TEntity>> ToListAsync() => await _query.ToListAsync();
}

View File

@ -0,0 +1,9 @@
namespace EnvelopeGenerator.Infrastructure;
public static class QueryExecutorExtension
{
public static QueryExecutor<TEntity> ToExecutor<TEntity>(this IQueryable<TEntity> queryable) where TEntity : class
{
return new QueryExecutor<TEntity>(queryable);
}
}

View File

@ -10,44 +10,21 @@ public sealed class SQLExecutor<T> : ISQLExecutor<T> where T : class
private readonly IServiceProvider _provider;
public SQLExecutor(EGDbContext context)
public SQLExecutor(EGDbContext context, IServiceProvider provider)
{
_context = context;
_provider = provider;
}
public async Task<T?> ExecuteFirstAsync(string sql, CancellationToken cancellation = default, params object[] parameters)
=> await _context
.Set<T>()
.FromSqlRaw(sql, parameters)
.FirstOrDefaultAsync(cancellation);
public IQueryExecutor<T> Execute(string sql, CancellationToken cancellation = default, params object[] parameters)
=> _context
.Set<T>()
.FromSqlRaw(sql, parameters)
.ToExecutor();
public async Task<T?> ExecuteSingleAsync(string sql, CancellationToken cancellation = default, params object[] parameters)
=> await _context
.Set<T>()
.FromSqlRaw(sql, parameters)
.SingleOrDefaultAsync(cancellation);
public async Task<IEnumerable<T>> ExecuteAllAsync(string sql, CancellationToken cancellation = default, params object[] parameters)
=> await _context
.Set<T>()
.FromSqlRaw(sql, parameters)
.ToListAsync(cancellation);
public Task<T?> ExecuteFirstAsync<TSQL>(CancellationToken cancellation = default, params object[] parameters) where TSQL : ISQL<T>
public IQueryExecutor<T> Execute<TSQL>(CancellationToken cancellation = default, params object[] parameters) where TSQL : ISQL<T>
{
var sql = _provider.GetRequiredService<TSQL>();
return ExecuteFirstAsync(sql.Raw);
}
public Task<T?> ExecuteSingleAsync<TSQL>(CancellationToken cancellation = default, params object[] parameters) where TSQL : ISQL<T>
{
var sql = _provider.GetRequiredService<TSQL>();
return ExecuteSingleAsync(sql.Raw);
}
public Task<IEnumerable<T>> ExecuteAllAsync<TSQL>(CancellationToken cancellation = default, params object[] parameters) where TSQL : ISQL<T>
{
var sql = _provider.GetRequiredService<TSQL>();
return ExecuteAllAsync(sql.Raw);
return Execute(sql.Raw);
}
}