using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Microsoft.EntityFrameworkCore; using SharedKernel.Results; using GameGenreEntity = Domain.Entities.Store.GameGenre; namespace Application.Features.Admin.Store.GameGenre.Save; public sealed class Handler(IAppDbContext db) : ICommandHandler> { public async Task> Handle(Command request, CancellationToken ct) { var items = request.Items; var dbRows = await db.GameGenre.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 inUse = await db.GameGenreMap.AsNoTracking().AnyAsync(c => deleteIDs.Contains(c.GameGenreID), ct); if (inUse) { return Result.Failure(Error.Conflict("GameGenre.InUse", "게임에 연결된 장르는 삭제할 수 없습니다. 먼저 해당 게임에서 장르 선택을 해제하세요.")); } db.GameGenre.RemoveRange(deleteTargets); } ushort inserted = 0; ushort updated = 0; foreach (var row in items) { if (string.IsNullOrWhiteSpace(row.KorName)) { return Result.Failure(Error.Problem("GameGenre.KorNameRequired", "장르 한글명은 필수입니다.")); } // 신규 추가 if (!row.ID.HasValue || row.ID.Value <= 0) { if (await db.GameGenre.AnyAsync(c => c.KorName == row.KorName, ct)) { return Result.Failure(Error.Conflict("GameGenre.DuplicateKorName", $"`{row.KorName}`는 이미 등록된 장르입니다.")); } db.GameGenre.Add(GameGenreEntity.Create(row.KorName, row.EngName, row.Order, row.IsActive)); inserted++; continue; } // 수정 if (!dbByID.TryGetValue(row.ID.Value, out var existing)) { return Result.Failure(Error.NotFound("GameGenre.NotFound", $"존재하지 않는 ID: {row.ID.Value}")); } if (existing.KorName != row.KorName && await db.GameGenre.AnyAsync(c => c.KorName == row.KorName, ct)) { return Result.Failure(Error.Conflict("GameGenre.DuplicateKorName", $"`{row.KorName}`는 이미 등록된 장르입니다.")); } existing.Update(row.KorName, row.EngName, row.Order, row.IsActive); updated++; } var deleted = (ushort)deleteTargets.Count; await db.SaveChangesAsync(ct); return Result.Success(new Response(inserted, updated, deleted)); } }