using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Microsoft.EntityFrameworkCore; namespace Application.Features.Api.Member.Items.Equipped; /// /// 여러 회원의 장착 지위 아이템을 한 번에 조회한다 (댓글/채팅/프로필 목록 렌더용). /// 만료(ExpiresAt 경과)·회수 아이템은 제외한다. /// internal sealed class Handler(IAppDbContext db) : IQueryHandler { private const int MaxIDs = 200; public async Task Handle(Query request, CancellationToken ct) { var ids = request.MemberIDs.Where(id => id > 0).Distinct().Take(MaxIDs).ToList(); if (ids.Count == 0) { return new Response([]); } var now = DateTime.UtcNow; var rows = await db.MemberItem.AsNoTracking() .Include(i => i.Product) .Where(i => ids.Contains(i.MemberID) && i.IsEquipped && i.EquipSlot != null && i.RevokedAt == null && (i.ExpiresAt == null || i.ExpiresAt > now)) .Select(i => new { i.MemberID, Slot = i.EquipSlot!.Value, i.Kind, ProductName = i.Product!.Name, i.Product.EffectPayload, i.Product.Thumbnail }) .ToListAsync(ct); var members = rows .GroupBy(r => r.MemberID) .Select(g => new Response.MemberEquip( g.Key, g.OrderBy(x => x.Slot) .Select(x => new Response.EquippedItem(x.Slot, x.Kind, x.ProductName, x.EffectPayload, x.Thumbnail)) .ToList())) .ToList(); return new Response(members); } }