Handler.cs 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. using Application.Abstractions.Data;
  2. using Application.Abstractions.Messaging;
  3. using Microsoft.EntityFrameworkCore;
  4. namespace Application.Features.Api.Member.Items.Equipped;
  5. /// <summary>
  6. /// 여러 회원의 장착 지위 아이템을 한 번에 조회한다 (댓글/채팅/프로필 목록 렌더용).
  7. /// 만료(ExpiresAt 경과)·회수 아이템은 제외한다.
  8. /// </summary>
  9. internal sealed class Handler(IAppDbContext db) : IQueryHandler<Query, Response>
  10. {
  11. private const int MaxIDs = 200;
  12. public async Task<Response> Handle(Query request, CancellationToken ct)
  13. {
  14. var ids = request.MemberIDs.Where(id => id > 0).Distinct().Take(MaxIDs).ToList();
  15. if (ids.Count == 0)
  16. {
  17. return new Response([]);
  18. }
  19. var now = DateTime.UtcNow;
  20. var rows = await db.MemberItem.AsNoTracking()
  21. .Include(i => i.Product)
  22. .Where(i => ids.Contains(i.MemberID)
  23. && i.IsEquipped
  24. && i.EquipSlot != null
  25. && i.RevokedAt == null
  26. && (i.ExpiresAt == null || i.ExpiresAt > now))
  27. .Select(i => new
  28. {
  29. i.MemberID,
  30. Slot = i.EquipSlot!.Value,
  31. i.Kind,
  32. ProductName = i.Product!.Name,
  33. i.Product.EffectPayload,
  34. i.Product.Thumbnail
  35. })
  36. .ToListAsync(ct);
  37. var members = rows
  38. .GroupBy(r => r.MemberID)
  39. .Select(g => new Response.MemberEquip(
  40. g.Key,
  41. g.OrderBy(x => x.Slot)
  42. .Select(x => new Response.EquippedItem(x.Slot, x.Kind, x.ProductName, x.EffectPayload, x.Thumbnail))
  43. .ToList()))
  44. .ToList();
  45. return new Response(members);
  46. }
  47. }