fix(pack): /pack/info reads ItemId via shadow FK, not nav property
PackController.Info's ownedItemsByItemId projection used `i.Item.Id` to key the dict — EF translates that to the FK column today, but any future model change that breaks the nav→column mapping would fall back to client eval and collapse every key to 0 (the default Item constructor's Id), silently hiding every tutorial pack via item_number=0. EF.Property<int> reads the shadow FK directly and is robust to nav changes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -63,10 +63,18 @@ public class PackController : SVSimController
|
||||
// OwnedItemEntry is [Owned] by Viewer, and EF refuses to track owned entities without
|
||||
// their owner in the result. Project to primitive pairs in the database query before
|
||||
// materialising into the dictionary — no entity tracking, single round-trip.
|
||||
//
|
||||
// Use EF.Property<int>(i, "ItemId") to read the shadow FK directly instead of going
|
||||
// through the OwnedItemEntry.Item nav. The nav route works today (EF translates
|
||||
// `i.Item.Id` to the FK column), but a future model change that renames the FK or
|
||||
// breaks the nav→column mapping would silently fall back to client eval — where
|
||||
// `i.Item.Id` returns 0 for every row (the default-initialised ItemEntry) and the
|
||||
// dictionary collapses every ticket to item_number=0. Shadow-FK access bypasses
|
||||
// that hazard entirely.
|
||||
var ownedItemsByItemId = await _db.Viewers
|
||||
.Where(v => v.Id == viewerId)
|
||||
.SelectMany(v => v.Items)
|
||||
.Select(i => new { ItemId = (long)i.Item.Id, i.Count })
|
||||
.Select(i => new { ItemId = (long)EF.Property<int>(i, "ItemId"), i.Count })
|
||||
.ToDictionaryAsync(x => x.ItemId, x => x.Count);
|
||||
|
||||
return new PackInfoResponse
|
||||
|
||||
Reference in New Issue
Block a user