Add SP-based update/delete for Catalogs, new endpoints
Added support for updating and deleting Catalog records via SQL Server stored procedures. Introduced PUT /catalogs/sp and DELETE /catalogs/sp/{id} endpoints in CatalogsController. Extended service and repository interfaces and implementations to handle stored procedure operations. Added Microsoft.Data.SqlClient package for direct SQL execution. Repository checks for record existence before SP calls to prevent unintended behavior.
This commit is contained in:
@@ -50,6 +50,17 @@ public class CatalogsController : ControllerBase
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
[HttpPut("sp")]
|
||||
public async Task<ActionResult<CatalogDto>> UpdateWithStoredProcedure(CatalogDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
var updated = await _service.UpdateWithStoredProcedureAsync(dto, cancellationToken);
|
||||
if (updated == null)
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
return Ok(updated);
|
||||
}
|
||||
|
||||
[HttpDelete("{id:int}")]
|
||||
public async Task<IActionResult> Delete(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -60,4 +71,15 @@ public class CatalogsController : ControllerBase
|
||||
}
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
[HttpDelete("sp/{id:int}")]
|
||||
public async Task<IActionResult> DeleteWithStoredProcedure(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
var deleted = await _service.DeleteWithStoredProcedureAsync(id, cancellationToken);
|
||||
if (!deleted)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,8 +40,20 @@ public class CatalogService : ICatalogService
|
||||
return await _repository.UpdateAsync(id, domainItem, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<CatalogDto?> UpdateWithStoredProcedureAsync(CatalogDto dto, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var domainItem = _mapper.Map<Catalog>(dto);
|
||||
var updated = await _repository.UpdateWithStoredProcedureAsync(domainItem, cancellationToken);
|
||||
return updated == null ? null : _mapper.Map<CatalogDto>(updated);
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(int id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await _repository.DeleteAsync(id, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteWithStoredProcedureAsync(int id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await _repository.DeleteWithStoredProcedureAsync(id, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,5 +6,7 @@ public interface ICatalogService
|
||||
Task<CatalogDto?> GetByIdAsync(int id, CancellationToken cancellationToken = default);
|
||||
Task<CatalogDto> CreateAsync(CatalogDto dto, CancellationToken cancellationToken = default);
|
||||
Task<bool> UpdateAsync(int id, CatalogDto dto, CancellationToken cancellationToken = default);
|
||||
Task<CatalogDto?> UpdateWithStoredProcedureAsync(CatalogDto dto, CancellationToken cancellationToken = default);
|
||||
Task<bool> DeleteAsync(int id, CancellationToken cancellationToken = default);
|
||||
Task<bool> DeleteWithStoredProcedureAsync(int id, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -8,5 +8,7 @@ public interface ICatalogRepository
|
||||
Task<Catalog?> GetByIdAsync(int id, CancellationToken cancellationToken = default);
|
||||
Task<Catalog> AddAsync(Catalog catalog, CancellationToken cancellationToken = default);
|
||||
Task<bool> UpdateAsync(int id, Catalog catalog, CancellationToken cancellationToken = default);
|
||||
Task<Catalog?> UpdateWithStoredProcedureAsync(Catalog catalog, CancellationToken cancellationToken = default);
|
||||
Task<bool> DeleteAsync(int id, CancellationToken cancellationToken = default);
|
||||
Task<bool> DeleteWithStoredProcedureAsync(int id, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -2,7 +2,9 @@ using AutoMapper;
|
||||
using DbFirst.Domain.DomainEntities;
|
||||
using DbFirst.Domain.Repositories;
|
||||
using DbFirst.Infrastructure.ScaffoldEntities;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Data;
|
||||
|
||||
namespace DbFirst.Infrastructure.Repositories;
|
||||
|
||||
@@ -51,6 +53,35 @@ public class CatalogRepository : ICatalogRepository
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<Catalog?> UpdateWithStoredProcedureAsync(Catalog catalog, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// ensure the record exists by CAT_TITLE to avoid insert behavior of the SP
|
||||
var exists = await _db.TbmyCatalogs.AsNoTracking().AnyAsync(x => x.CatTitle == catalog.CatTitle, cancellationToken);
|
||||
if (!exists)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
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 guidOutParam = new SqlParameter("@GUID", SqlDbType.Int) { Direction = ParameterDirection.Output };
|
||||
|
||||
await _db.Database.ExecuteSqlRawAsync(
|
||||
"EXEC dbo.PRTBMY_CATALOG_UPDATE @CAT_TITLE, @CAT_STRING, @CHANGED_WHO, @GUID OUTPUT",
|
||||
parameters: new[] { catTitleParam, catStringParam, changedWhoParam, guidOutParam },
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
if (guidOutParam.Value == DBNull.Value)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var guid = (int)guidOutParam.Value;
|
||||
var entity = await _db.TbmyCatalogs.AsNoTracking().FirstOrDefaultAsync(x => x.Guid == guid, cancellationToken);
|
||||
return entity == null ? new Catalog { Guid = guid, CatTitle = catalog.CatTitle, CatString = catalog.CatString, ChangedWho = catalog.ChangedWho } : _mapper.Map<Catalog>(entity);
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(int id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var entity = await _db.TbmyCatalogs.FirstOrDefaultAsync(x => x.Guid == id, cancellationToken);
|
||||
@@ -63,4 +94,21 @@ public class CatalogRepository : ICatalogRepository
|
||||
await _db.SaveChangesAsync(cancellationToken);
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteWithStoredProcedureAsync(int id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var exists = await _db.TbmyCatalogs.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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user