Handler.cs 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. using Application.Abstractions.Messaging;
  2. using Application.Abstractions.Data;
  3. using Application.Abstractions.Cache;
  4. using Microsoft.EntityFrameworkCore;
  5. using Domain.Entities.Page.Faq;
  6. namespace Application.Features.Admin.Faq.Category.Save
  7. {
  8. public sealed class Handler(IAppDbContext db, ICacheService cache) : ICommandHandler<Command, Response>
  9. {
  10. public async Task<Response> Handle(Command request, CancellationToken ct)
  11. {
  12. var items = request.Items;
  13. var dbRows = await db.FaqCategory.ToListAsync(ct);
  14. var dbByID = dbRows.ToDictionary(c => c.ID);
  15. // 값이 있는 것만 추출
  16. var requestIDs = items.Where(c => c.ID.HasValue && c.ID.Value > 0).Select(c => c.ID!.Value).ToHashSet();
  17. // 삭제 대상 조회
  18. var deleteTargets = dbRows.Where(x => !requestIDs.Contains(x.ID)).ToList();
  19. if (deleteTargets.Count > 0)
  20. {
  21. var deleteIDs = deleteTargets.Select(c => c.ID).ToList();
  22. var hasItems = await db.FaqItem.AsNoTracking().AnyAsync(c => deleteIDs.Contains(c.CategoryID), ct);
  23. if (hasItems)
  24. {
  25. throw new InvalidOperationException("FAQ가 등록된 분류는 삭제할 수 없습니다. 먼저 해당 FAQ를 삭제하세요.");
  26. }
  27. db.FaqCategory.RemoveRange(deleteTargets);
  28. }
  29. ushort inserted = 0;
  30. ushort updated = 0;
  31. ushort deleted = 0;
  32. foreach(var row in items)
  33. {
  34. // 신규 추가
  35. if (!row.ID.HasValue || row.ID.Value <= 0)
  36. {
  37. // Code 중복 검사
  38. if (await db.FaqCategory.AnyAsync(c => c.Code == row.Code && c.ID != row.ID, ct))
  39. {
  40. throw new InvalidOperationException($"`{row.Code}`는 이미 등록되었습니다.");
  41. }
  42. db.FaqCategory.Add(
  43. FaqCategory.Create(row.Code, row.Subject, row.Order, row.IsActive)
  44. );
  45. inserted++;
  46. continue;
  47. }
  48. // 수정
  49. if (!dbByID.TryGetValue(row.ID.Value, out var existing))
  50. {
  51. throw new InvalidOperationException($"존재하지 않는 ID: {row.ID.Value}");
  52. }
  53. // Code가 변경된 경우에만 중복 검사
  54. if (existing.Code != row.Code && await db.FaqCategory.AnyAsync(c => c.Code == row.Code, ct))
  55. {
  56. throw new InvalidOperationException($"`{row.Code}`는 이미 등록되었습니다.");
  57. }
  58. existing.Update(row.Code, row.Subject, row.Order, row.IsActive);
  59. updated++;
  60. }
  61. deleted = (ushort)deleteTargets.Count;
  62. await db.SaveChangesAsync(ct);
  63. await cache.RemoveAsync(CacheKeys.FaqCategoryActive, ct);
  64. await cache.RemoveByPrefixAsync("faq:item:", ct);
  65. return new Response(inserted, updated, deleted);
  66. }
  67. }
  68. }