Handler.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. using Application.Abstractions.Data;
  2. using Application.Abstractions.Messaging;
  3. using Domain.Entities.Wallets.ValueObject;
  4. using Microsoft.EntityFrameworkCore;
  5. namespace Application.Features.Admin.Donation.List.Search;
  6. public sealed class Handler(IAppDbContext db) : IQueryHandler<Query, Response>
  7. {
  8. public async Task<Response> Handle(Query request, CancellationToken ct)
  9. {
  10. var query = db.Donation.AsNoTracking().Include(x => x.Sponsor).Include(x => x.Receiver).AsQueryable();
  11. // 키워드 검색
  12. if (!string.IsNullOrWhiteSpace(request.Keyword))
  13. {
  14. query = request.Search switch
  15. {
  16. 1 => query.Where(x => x.Sponsor != null && x.Sponsor.ID.ToString().Contains(request.Keyword)),
  17. 2 => query.Where(x => x.Sponsor != null && x.Sponsor.SID.Contains(request.Keyword)),
  18. 3 => query.Where(x => x.Sponsor != null && x.Sponsor.Name != null && x.Sponsor.Name.Contains(request.Keyword)),
  19. 4 => query.Where(x => x.Receiver != null && x.Receiver.ID.ToString().Contains(request.Keyword)),
  20. 5 => query.Where(x => x.Receiver != null && x.Receiver.SID.Contains(request.Keyword)),
  21. 6 => query.Where(x => x.Receiver != null && x.Receiver.Name != null && x.Receiver.Name.Contains(request.Keyword)),
  22. 7 => query.Where(x => x.SendName.Contains(request.Keyword)),
  23. _ => query
  24. };
  25. }
  26. // 날짜 필터
  27. if (!string.IsNullOrWhiteSpace(request.StartAt) && DateTime.TryParse(request.StartAt, out var startAt))
  28. {
  29. query = query.Where(x => x.CreatedAt >= startAt);
  30. }
  31. if (!string.IsNullOrWhiteSpace(request.EndAt) && DateTime.TryParse(request.EndAt, out var endAt))
  32. {
  33. query = query.Where(x => x.CreatedAt <= endAt);
  34. }
  35. var total = await query.CountAsync(ct);
  36. var skip = (request.Page - 1) * request.PerPage;
  37. var list = await query
  38. .OrderByDescending(x => x.ID)
  39. .Skip(skip)
  40. .Take(request.PerPage)
  41. .Select(x => new
  42. {
  43. x.ID,
  44. x.Amount,
  45. x.Message,
  46. x.SendName,
  47. x.IsTest,
  48. x.CreatedAt,
  49. x.SponsorMemberID,
  50. x.ReceiverMemberID,
  51. SponsorID = x.Sponsor != null ? x.Sponsor.ID : 0,
  52. SponsorEmail = x.Sponsor != null ? x.Sponsor.Email : string.Empty,
  53. SponsorName = x.Sponsor != null ? x.Sponsor.Name : null,
  54. SponsorSID = x.Sponsor != null ? x.Sponsor.SID : null,
  55. ReceiverID = x.Receiver != null ? x.Receiver.ID : 0,
  56. ReceiverEmail = x.Receiver != null ? x.Receiver.Email : string.Empty,
  57. ReceiverName = x.Receiver != null ? x.Receiver.Name : null,
  58. ReceiverSID = x.Receiver != null ? x.Receiver.SID : null
  59. })
  60. .ToListAsync(ct);
  61. // 관련 회원의 지갑 잔액 일괄 조회 (행별 N+1 방지)
  62. var memberIDs = list.Select(x => x.SponsorMemberID).Concat(list.Select(x => x.ReceiverMemberID)).Distinct().ToArray();
  63. var wallets = await db.Wallet
  64. .AsNoTracking()
  65. .Where(w => memberIDs.Contains(w.MemberID))
  66. .Include(w => w.Balances)
  67. .ToListAsync(ct);
  68. var balanceByMember = wallets.ToDictionary(
  69. w => w.MemberID,
  70. w => new
  71. {
  72. Total = (long)w.Balances.Where(b => b.Type != WalletBalanceType.Locked).Sum(b => b.Amount.Value),
  73. Donation = (long)(w.Balances.FirstOrDefault(b => b.Type == WalletBalanceType.Donation)?.Amount.Value ?? 0)
  74. });
  75. var rows = list.Select((x, idx) => new Response.Row
  76. {
  77. Num = total - skip - idx,
  78. ID = x.ID,
  79. Amount = x.Amount,
  80. Message = x.Message,
  81. SendName = x.SendName,
  82. IsTest = x.IsTest,
  83. Sponsor = new Response.MemberInfo
  84. {
  85. ID = x.SponsorID,
  86. Email = x.SponsorEmail,
  87. Name = x.SponsorName,
  88. SID = x.SponsorSID
  89. },
  90. Receiver = new Response.MemberInfo
  91. {
  92. ID = x.ReceiverID,
  93. Email = x.ReceiverEmail,
  94. Name = x.ReceiverName,
  95. SID = x.ReceiverSID
  96. },
  97. SponsorBalance = balanceByMember.TryGetValue(x.SponsorMemberID, out var sb) ? sb.Total : 0L,
  98. ReceiverDonationBalance = balanceByMember.TryGetValue(x.ReceiverMemberID, out var rb) ? rb.Donation : 0L,
  99. CreatedAt = x.CreatedAt
  100. }).ToList();
  101. return new Response
  102. {
  103. Total = total,
  104. List = rows
  105. };
  106. }
  107. }