using Azure; using DbFirst.Domain.Entities; using DbFirst.Domain.Repositories; using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Data; using System.Text; using System.Threading.Channels; using static Microsoft.EntityFrameworkCore.DbLoggerCategory; using static System.Runtime.InteropServices.JavaScript.JSType; 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 CRUD base service adds little value in your case: Pros: • Less boilerplate for simple entities without special logic. • Uniform CRUD signatures. Cons/Practical here: • Domain logic differs per entity(unique title check, setting audit fields, forbidding title changes, stored procs with output GUID). • Generic services tend to be diluted by virtual methods/hooks for special cases—ending up with per-entity overrides and little real gain. • With stored procedures and output parameters, the pattern doesn’t fit cleanly because operations aren’t symmetric (separate procs for insert/update/delete). Conclusion: For this solution a generic service would be more overhead than benefit. If you later have multiple very similar entities without special logic, you could consider a lightweight generic interface/base; for now, the specialized service implementation is cleaner. */ 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, 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); await _db.Database.ExecuteSqlRawAsync( "EXEC dbo.PRTBMY_CATALOG_UPDATE @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 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; } }