using DbFirst.Domain; using DbFirst.Domain.Entities; using DbFirst.Domain.Repositories; using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using System.Data; namespace DbFirst.Infrastructure.Repositories; // TODO: instead of creating implementation of repository per entity, consider using generic repository pattern (eg. Repository) to reduce code duplication. /* Copilot's Response: A generic Repository isn’t really worthwhile here: • Reads from the view are generic, but inserts/updates/deletes go through stored procedures with special parameters/output GUIDs.You’d need lots of exceptions/overrides—little gain. • Operations aren’t symmetric (separate procs for insert/update/delete with output handling and reload), so a one-size-fits-all CRUD pattern doesn’t fit well. • Better to keep the specialized repo.If you want reuse, extract small helpers (e.g., for proc calls/output parameters/reload) instead of forcing a generic repository. */ public class CatalogRepository : ICatalogRepository { private readonly ApplicationDbContext _db; public CatalogRepository(ApplicationDbContext db) { _db = db; } public async Task> GetAllAsync(CancellationToken cancellationToken = default) { return await _db.VwmyCatalogs.AsNoTracking().ToListAsync(cancellationToken); } public async Task GetByIdAsync(int id, CancellationToken cancellationToken = default) { return await _db.VwmyCatalogs.AsNoTracking().FirstOrDefaultAsync(x => x.Guid == id, cancellationToken); } public async Task GetByTitleAsync(string title, CancellationToken cancellationToken = default) { return await _db.VwmyCatalogs.AsNoTracking().FirstOrDefaultAsync(x => x.CatTitle == title, cancellationToken); } public async Task InsertAsync(VwmyCatalog catalog, CancellationToken cancellationToken = default) { var guidParam = new SqlParameter("@GUID", SqlDbType.Int) { Direction = ParameterDirection.Output }; var catTitleParam = new SqlParameter("@CAT_TITLE", catalog.CatTitle); var catStringParam = new SqlParameter("@CAT_STRING", catalog.CatString); var addedWhoParam = new SqlParameter("@ADDED_WHO", (object?)catalog.AddedWho ?? DBNull.Value); await _db.Database.ExecuteSqlRawAsync( "EXEC dbo.PRTBMY_CATALOG_INSERT @CAT_TITLE, @CAT_STRING, @ADDED_WHO, @GUID OUTPUT", parameters: new[] { catTitleParam, catStringParam, addedWhoParam, guidParam }, cancellationToken: cancellationToken); if (guidParam.Value == DBNull.Value) { throw new InvalidOperationException("Failed to insert catalog via stored procedure."); } var guid = (int)guidParam.Value; var created = await _db.VwmyCatalogs.AsNoTracking().FirstOrDefaultAsync(x => x.Guid == guid, cancellationToken); if (created == null) { throw new InvalidOperationException("Inserted catalog could not be loaded from view."); } return created; } public async Task UpdateAsync(int id, VwmyCatalog catalog, CatalogUpdateProcedure procedure, CancellationToken cancellationToken = default) { catalog.Guid = id; var guidParam = new SqlParameter("@GUID", SqlDbType.Int) { Direction = ParameterDirection.Output }; var catTitleParam = new SqlParameter("@CAT_TITLE", catalog.CatTitle); var catStringParam = new SqlParameter("@CAT_STRING", catalog.CatString); var changedWhoParam = new SqlParameter("@CHANGED_WHO", (object?)catalog.ChangedWho ?? DBNull.Value); var procName = procedure == CatalogUpdateProcedure.Save ? "PRTBMY_CATALOG_SAVE" : "PRTBMY_CATALOG_UPDATE"; await _db.Database.ExecuteSqlRawAsync( $"EXEC dbo.{procName} @CAT_TITLE, @CAT_STRING, @CHANGED_WHO, @GUID OUTPUT", parameters: new[] { catTitleParam, catStringParam, changedWhoParam, guidParam }, cancellationToken: cancellationToken); if (guidParam.Value == DBNull.Value) { return null; } var guid = (int)guidParam.Value; if (guid == 0) { return null; } return await _db.VwmyCatalogs.AsNoTracking().FirstOrDefaultAsync(x => x.Guid == guid, cancellationToken); } public async Task UpdateAsync(int id, VwmyCatalog catalog, CancellationToken cancellationToken = default) { return await UpdateAsync(id, catalog, CatalogUpdateProcedure.Update, cancellationToken); } public async Task DeleteAsync(int id, CancellationToken cancellationToken = default) { var exists = await _db.VwmyCatalogs.AsNoTracking().AnyAsync(x => x.Guid == id, cancellationToken); if (!exists) { return false; } var guidParam = new SqlParameter("@GUID", id); await _db.Database.ExecuteSqlRawAsync( "EXEC dbo.PRTBMY_CATALOG_DELETE @GUID", parameters: new[] { guidParam }, cancellationToken: cancellationToken); return true; } }