using Application.Abstractions.Messaging; using Application.Abstractions.Data; 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) { throw new InvalidOperationException("게시판이 등록된 분류는 삭제할 수 없습니다. 먼저 해당 게시판을 삭제하세요."); } 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)) { throw new InvalidOperationException($"`{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)) { throw new InvalidOperationException($"존재하지 않는 ID: {row.ID.Value}"); } if (existing.Code != row.Code && await db.BoardGroup.AnyAsync(c => c.Code == row.Code, ct)) { throw new InvalidOperationException($"`{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 new Response(inserted, updated, deleted); } } }