From f18cfb58b889e1b3aeae434099d07e7d9f281920 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Sat, 4 Jul 2026 10:16:10 -0400 Subject: [PATCH] feat(rank): viewer repo LoadForRankProgressAsync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split-query load of Classes (for class XP) + RankProgress (for rank grant) so RankBattleController.Finish uses a single viewer read. Test factory's ReferenceDataImporter.ImportAllAsync already seeds RankInfo — no test helper needed. Co-Authored-By: Claude Opus 4.7 --- .../Repositories/Viewer/IViewerRepository.cs | 8 ++++++++ SVSim.Database/Repositories/Viewer/ViewerRepository.cs | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/SVSim.Database/Repositories/Viewer/IViewerRepository.cs b/SVSim.Database/Repositories/Viewer/IViewerRepository.cs index ea93d8ad..cea51a27 100644 --- a/SVSim.Database/Repositories/Viewer/IViewerRepository.cs +++ b/SVSim.Database/Repositories/Viewer/IViewerRepository.cs @@ -59,6 +59,14 @@ public interface IViewerRepository /// Task LoadForBattleXpGrantAsync(long viewerId, CancellationToken ct = default); + /// + /// Load a viewer with the joins 's Finish + /// needs: Classes (for the class-XP grant) + RankProgress (for the rank grant). Split-query + /// per project_ef_split_query to avoid the cartesian explosion when both nav + /// collections are populated on the same viewer. + /// + Task LoadForRankProgressAsync(long viewerId, CancellationToken ct = default); + /// Sets Viewer.GuildId to . No-op if the viewer does not exist. Task SetGuildIdAsync(long viewerId, int guildId, CancellationToken ct = default); diff --git a/SVSim.Database/Repositories/Viewer/ViewerRepository.cs b/SVSim.Database/Repositories/Viewer/ViewerRepository.cs index ed06edef..9fa22386 100644 --- a/SVSim.Database/Repositories/Viewer/ViewerRepository.cs +++ b/SVSim.Database/Repositories/Viewer/ViewerRepository.cs @@ -281,6 +281,16 @@ public class ViewerRepository : IViewerRepository .FirstOrDefaultAsync(v => v.Id == viewerId, ct); } + public Task LoadForRankProgressAsync(long viewerId, CancellationToken ct = default) + { + return _dbContext.Set() + .Include(v => v.Classes) + .ThenInclude(c => c.Class) + .Include(v => v.RankProgress) + .AsSplitQuery() + .FirstOrDefaultAsync(v => v.Id == viewerId, ct); + } + public async Task SetGuildIdAsync(long viewerId, int guildId, CancellationToken ct = default) { var viewer = await _dbContext.Set()