using Application.Abstractions.Messaging; using Application.Abstractions.Data; using SharedKernel.Results; using Microsoft.EntityFrameworkCore; namespace Application.Features.Admin.Forum.BoardGroup.Save; public sealed class Handler(IAppDbContext db) : ICommandHandler> { public async Task> Handle(Command request, CancellationToken ct) { var items = request.Items; var dbRows = await db.BoardGroup.ToListAsync(ct); var dbByID = dbRows.ToDictionary(c => c.ID); var requestIDs = items.Where(c => c.ID.HasValue && c.ID.Value > 0).Select(c => c.ID!.Value).ToHashSet(); // 삭제 대상 조회 var deleteTargets = dbRows.Where(x => !requestIDs.Contains(x.ID)).ToList(); if (deleteTargets.Count > 0) { var deleteIDs = deleteTargets.Select(c => c.ID).ToList(); var hasBoards = await db.Board.AsNoTracking().AnyAsync(c => deleteIDs.Contains(c.BoardGroupID), ct); if (hasBoards) { return Result.Failure(Error.Conflict("BoardGroup.HasBoards", "게시판이 등록된 분류는 삭제할 수 없습니다. 먼저 해당 게시판을 삭제하세요.")); } db.BoardGroup.RemoveRange(deleteTargets); } ushort inserted = 0; ushort updated = 0; ushort deleted = 0; foreach (var row in items) { // 신규 추가 if (!row.ID.HasValue || row.ID.Value <= 0) { if (await db.BoardGroup.AnyAsync(c => c.Code == row.Code, ct)) { return Result.Failure(Error.Conflict("BoardGroup.DuplicateCode", $"`{row.Code}`는 이미 등록되었습니다.")); } db.BoardGroup.Add(new Domain.Entities.Forum.Boards.BoardGroup { Code = row.Code, Name = row.Name, Order = row.Order }); inserted++; continue; } // 수정 if (!dbByID.TryGetValue(row.ID.Value, out var existing)) { return Result.Failure(Error.NotFound("BoardGroup.NotFound", $"존재하지 않는 ID: {row.ID.Value}")); } if (existing.Code != row.Code && await db.BoardGroup.AnyAsync(c => c.Code == row.Code, ct)) { return Result.Failure(Error.Conflict("BoardGroup.DuplicateCode", $"`{row.Code}`는 이미 등록되었습니다.")); } existing.Code = row.Code; existing.Name = row.Name; existing.Order = row.Order; existing.UpdatedAt = DateTime.UtcNow; updated++; } deleted = (ushort)deleteTargets.Count; await db.SaveChangesAsync(ct); return Result.Success(new Response(inserted, updated, deleted)); } }