Files
sql-utilities/src/Strata.SqlTools.EFCore/Services/QueryBreakdownRepository.cs
T

244 lines
8.6 KiB
C#

using Microsoft.EntityFrameworkCore;
using Strata.SqlTools.Breakdowns.SqlServer;
using Strata.SqlTools.EFCore.Abstractions;
using Strata.SqlTools.EFCore.Models;
namespace Strata.SqlTools.EFCore.Services;
/// <summary>
/// Interface for a generic repository pattern for QueryBreakdown entities.
/// Provides a simplified API for common database operations.
/// </summary>
public interface IQueryBreakdownRepository
{
/// <summary>
/// Adds a new QueryBreakdown to the repository and saves changes.
/// </summary>
/// <param name="queryBreakdown">The QueryBreakdown to add.</param>
/// <returns>The ID of the added entity.</returns>
Task<int> AddAsync(QueryBreakdown queryBreakdown);
/// <summary>
/// Retrieves a QueryBreakdown by ID and converts it from the entity.
/// </summary>
/// <param name="id">The ID of the QueryBreakdown entity.</param>
/// <returns>The QueryBreakdown, or null if not found.</returns>
Task<QueryBreakdown?> GetByIdAsync(int id);
/// <summary>
/// Retrieves a QueryBreakdownEntity by ID.
/// </summary>
/// <param name="id">The ID of the entity.</param>
/// <returns>The QueryBreakdownEntity, or null if not found.</returns>
Task<QueryBreakdownEntity?> GetEntityByIdAsync(int id);
/// <summary>
/// Gets all QueryBreakdowns.
/// </summary>
/// <returns>A list of all QueryBreakdowns.</returns>
Task<List<QueryBreakdown>> GetAllAsync();
/// <summary>
/// Gets all QueryBreakdownEntities.
/// </summary>
/// <returns>A list of all QueryBreakdownEntities.</returns>
Task<List<QueryBreakdownEntity>> GetAllEntitiesAsync();
/// <summary>
/// Updates an existing QueryBreakdown and saves changes.
/// </summary>
/// <param name="id">The ID of the entity to update.</param>
/// <param name="queryBreakdown">The updated QueryBreakdown.</param>
Task UpdateAsync(int id, QueryBreakdown queryBreakdown);
/// <summary>
/// Deletes a QueryBreakdown by ID and saves changes.
/// </summary>
/// <param name="id">The ID of the entity to delete.</param>
/// <returns>True if the entity was deleted; false if not found.</returns>
Task<bool> DeleteAsync(int id);
/// <summary>
/// Gets the count of all QueryBreakdown entities.
/// </summary>
/// <returns>The count of entities.</returns>
Task<int> GetCountAsync();
}
/// <summary>
/// Implementation of IQueryBreakdownRepository for managing QueryBreakdown entities in Entity Framework Core.
/// </summary>
public class QueryBreakdownRepository : IQueryBreakdownRepository
{
private readonly DbContext _context;
private readonly IQueryBreakdownMapper _mapper;
/// <summary>
/// Initializes a new instance of the QueryBreakdownRepository.
/// </summary>
/// <param name="context">The EF Core DbContext.</param>
/// <param name="mapper">The mapper for converting between QueryBreakdown and QueryBreakdownEntity.</param>
public QueryBreakdownRepository(DbContext context, IQueryBreakdownMapper mapper)
{
ArgumentNullException.ThrowIfNull(context);
ArgumentNullException.ThrowIfNull(mapper);
_context = context;
_mapper = mapper;
}
/// <summary>
/// Adds a new QueryBreakdown to the repository and saves changes.
/// </summary>
public async Task<int> AddAsync(QueryBreakdown queryBreakdown)
{
ArgumentNullException.ThrowIfNull(queryBreakdown);
var (entity, parameters, withClauses) = _mapper.MapToEntityWithRelations(queryBreakdown);
// Add the main entity
_context.Set<QueryBreakdownEntity>().Add(entity);
await _context.SaveChangesAsync();
// Add related entities with foreign key set
foreach (var param in parameters)
{
param.QueryBreakdownEntityId = entity.Id;
_context.Set<QueryParameterEntity>().Add(param);
}
foreach (var withClause in withClauses)
{
withClause.QueryBreakdownEntityId = entity.Id;
_context.Set<WithClauseEntity>().Add(withClause);
}
await _context.SaveChangesAsync();
return entity.Id;
}
/// <summary>
/// Retrieves a QueryBreakdown by ID and converts it from the entity.
/// </summary>
public async Task<QueryBreakdown?> GetByIdAsync(int id)
{
var entity = await _context.Set<QueryBreakdownEntity>()
.Include(e => e.Parameters)
.Include(e => e.WithClauses)
.FirstOrDefaultAsync(e => e.Id == id);
return entity != null ? _mapper.MapToDomainModelWithRelations(entity) : null;
}
/// <summary>
/// Retrieves a QueryBreakdownEntity by ID.
/// </summary>
public async Task<QueryBreakdownEntity?> GetEntityByIdAsync(int id)
{
return await _context.Set<QueryBreakdownEntity>()
.FirstOrDefaultAsync(e => e.Id == id);
}
/// <summary>
/// Gets all QueryBreakdowns.
/// </summary>
public async Task<List<QueryBreakdown>> GetAllAsync()
{
var entities = await _context.Set<QueryBreakdownEntity>().ToListAsync();
return entities.ConvertAll(e => _mapper.MapToDomainModel(e));
}
/// <summary>
/// Gets all QueryBreakdownEntities.
/// </summary>
public async Task<List<QueryBreakdownEntity>> GetAllEntitiesAsync()
{
return await _context.Set<QueryBreakdownEntity>().ToListAsync();
}
/// <summary>
/// Updates an existing QueryBreakdown and saves changes.
/// </summary>
public async Task UpdateAsync(int id, QueryBreakdown queryBreakdown)
{
ArgumentNullException.ThrowIfNull(queryBreakdown);
var entity = await _context.Set<QueryBreakdownEntity>().FirstOrDefaultAsync(e => e.Id == id);
if (entity == null)
{
throw new InvalidOperationException($"QueryBreakdown with ID {id} not found.");
}
var updatedEntity = _mapper.MapToEntity(queryBreakdown);
// Update the main entity
entity.SelectClause = updatedEntity.SelectClause;
entity.SelectClauseComment = updatedEntity.SelectClauseComment;
entity.FromClause = updatedEntity.FromClause;
entity.FromClauseComment = updatedEntity.FromClauseComment;
entity.WhereClause = updatedEntity.WhereClause;
entity.WhereClauseComment = updatedEntity.WhereClauseComment;
entity.GroupByClause = updatedEntity.GroupByClause;
entity.GroupByClauseComment = updatedEntity.GroupByClauseComment;
entity.HavingClause = updatedEntity.HavingClause;
entity.HavingClauseComment = updatedEntity.HavingClauseComment;
entity.OrderByClause = updatedEntity.OrderByClause;
entity.OrderByClauseComment = updatedEntity.OrderByClauseComment;
entity.WithClause = updatedEntity.WithClause;
entity.RawSql = updatedEntity.RawSql;
entity.SetupClausesJson = updatedEntity.SetupClausesJson;
entity.FinishClausesJson = updatedEntity.FinishClausesJson;
entity.ParametersJson = updatedEntity.ParametersJson;
entity.UpdatedAt = DateTime.UtcNow;
// Delete and recreate related entities
var existingParameters = _context.Set<QueryParameterEntity>().Where(p => p.QueryBreakdownEntityId == id);
_context.Set<QueryParameterEntity>().RemoveRange(existingParameters);
var existingWithClauses = _context.Set<WithClauseEntity>().Where(w => w.QueryBreakdownEntityId == id);
_context.Set<WithClauseEntity>().RemoveRange(existingWithClauses);
var (_, parameters, withClauses) = _mapper.MapToEntityWithRelations(queryBreakdown);
foreach (var param in parameters)
{
param.QueryBreakdownEntityId = id;
_context.Set<QueryParameterEntity>().Add(param);
}
foreach (var withClause in withClauses)
{
withClause.QueryBreakdownEntityId = id;
_context.Set<WithClauseEntity>().Add(withClause);
}
await _context.SaveChangesAsync();
}
/// <summary>
/// Deletes a QueryBreakdown by ID and saves changes.
/// </summary>
public async Task<bool> DeleteAsync(int id)
{
var entity = await _context.Set<QueryBreakdownEntity>().FirstOrDefaultAsync(e => e.Id == id);
if (entity == null)
{
return false;
}
_context.Set<QueryBreakdownEntity>().Remove(entity);
await _context.SaveChangesAsync();
return true;
}
/// <summary>
/// Gets the count of all QueryBreakdown entities.
/// </summary>
public async Task<int> GetCountAsync()
{
return await _context.Set<QueryBreakdownEntity>().CountAsync();
}
}