diff --git a/ECMJobRunner.Domain/Interfaces/ISQLExecutor.cs b/ECMJobRunner.Domain/Interfaces/ISQLExecutor.cs new file mode 100644 index 0000000..9059f65 --- /dev/null +++ b/ECMJobRunner.Domain/Interfaces/ISQLExecutor.cs @@ -0,0 +1,20 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace ECMJobRunner.Domain.Interfaces +{ + /// + /// Interface for executing SQL queries and mapping results to DTOs + /// + public interface ISQLExecutor + { + /// + /// Executes a SQL query and maps the result to the specified type + /// + /// The type to map the query result to + /// The SQL query to execute + /// Cancellation token + /// The mapped result or null if no result + Task ExecuteQueryAsync(string sql, CancellationToken cancellationToken = default); + } +} diff --git a/ECMJobRunner.Infrastructure/DependencyExtension.cs b/ECMJobRunner.Infrastructure/DependencyExtension.cs index 7eed1f6..5fdb885 100644 --- a/ECMJobRunner.Infrastructure/DependencyExtension.cs +++ b/ECMJobRunner.Infrastructure/DependencyExtension.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.DependencyInjection; using ECMJobRunner.Domain.Interfaces; using ECMJobRunner.Infrastructure.Data; using ECMJobRunner.Infrastructure.Repositories; +using ECMJobRunner.Infrastructure.Services; namespace ECMJobRunner.Infrastructure { @@ -43,6 +44,9 @@ namespace ECMJobRunner.Infrastructure services.AddScoped(); services.AddScoped(); + // Register SQL executor as scoped + services.AddScoped(); + return services; } @@ -70,6 +74,9 @@ namespace ECMJobRunner.Infrastructure services.AddScoped(); services.AddScoped(); + // Register SQL executor as scoped + services.AddScoped(); + return services; } #else @@ -96,6 +103,9 @@ namespace ECMJobRunner.Infrastructure services.AddScoped(); services.AddScoped(); + // Register SQL executor as scoped + services.AddScoped(); + return services; } #endif diff --git a/ECMJobRunner.Infrastructure/Services/SQLExecutor.cs b/ECMJobRunner.Infrastructure/Services/SQLExecutor.cs new file mode 100644 index 0000000..0b4d942 --- /dev/null +++ b/ECMJobRunner.Infrastructure/Services/SQLExecutor.cs @@ -0,0 +1,57 @@ +#if NET48 +using System.Data.Entity; +using System.Linq; +#else +using Microsoft.EntityFrameworkCore; +#endif +using ECMJobRunner.Domain.Interfaces; +using ECMJobRunner.Infrastructure.Data; +using System.Threading; +using System.Threading.Tasks; + +namespace ECMJobRunner.Infrastructure.Services +{ + /// + /// Entity Framework implementation of ISQLExecutor + /// Executes raw SQL queries and maps results to DTOs + /// + public class SQLExecutor : ISQLExecutor + { + private readonly JobRunnerDbContext _context; + + /// + /// Initializes a new instance of SQLExecutor + /// + /// The database context + public SQLExecutor(JobRunnerDbContext context) + { + _context = context; + } + + /// + /// Executes a SQL query and maps the result to the specified type + /// + /// The type to map the query result to + /// The SQL query to execute + /// Cancellation token + /// The mapped result or null if no result + public async Task ExecuteQueryAsync(string sql, CancellationToken cancellationToken = default) + { +#if NET48 + // Entity Framework 6 implementation + var result = await _context.Database + .SqlQuery(sql) + .FirstOrDefaultAsync(cancellationToken); + + return result; +#else + // Entity Framework Core implementation + var result = await _context.Database + .SqlQueryRaw(sql) + .FirstOrDefaultAsync(cancellationToken); + + return result; +#endif + } + } +}