SQL Server不同表关联方案:EF Core下游戏多类型道具库存设计
EF Core 游戏道具存储最优实现方案
方案1:表 per 层次结构(TPH)单表存储(最适合中小体量游戏)
TPH是EF Core默认支持的多态映射方案,所有类型的道具都存在同一张Items表中:
- 首先定义抽象基类
Item,封装所有道具共有的属性:Id、ItemType(枚举:Weapon/Armor/Potion)、Cost - 子类分别继承基类,扩展自身独有属性:
Weapon子类:Weight、Damage、DamageType、MinStrArmor子类:Weight、ArmorPoints、BodySlot、HardnessPotion子类:Type、Effect、EffectAmount
- EF Core会自动在表中生成
Discriminator字段区分道具类型,空值的独有字段会自动处理 - 背包表设计非常简单:
PlayerInventory表只需要存PlayerId、ItemId、Count、SlotIndex,直接和Items表做外键关联即可 - 查询全道具列表直接查
Items表即可,EF Core会自动映射为对应的子类实例,不需要手动聚合多表数据 - 优点:查询效率最高,关联逻辑最简单,背包操作无需判断类型
- 适用场景:道具类型不超过10种,单表字段总数不超过30的中小项目
方案2:基表 + 类型扩展表(TPT,适合大型游戏道具体系)
如果道具类型多、独有属性多,不想单表出现大量空字段,可以用TPT模式:
- 公共属性存在
Items基表,每个道具类型单独建扩展表:Weapons、Armors、Potions,扩展表主键和Items表的Id做一对一外键关联 - EF Core配置多态映射后,查询子类道具会自动做表联接,返回强类型子类实例
- 背包表同样只需要关联
Items表的Id,不需要存储类型标识,所有关联逻辑EF Core自动处理 - 优点:表结构规整,无冗余空字段,扩展新道具类型只需要新增扩展表,不需要修改基表结构
- 缺点:查询单类型道具会做表联接,性能略低于TPH
背包功能实现示例
两种方案下背包查询代码完全一致,不需要手动处理类型判断:
// 查询指定玩家的所有背包道具 var playerItems = await _dbContext.PlayerInventories .Where(x => x.PlayerId == currentPlayerId) .Include(x => x.Item) .OrderBy(x => x.SlotIndex) .ToListAsync(); // 遍历道具自动识别类型 foreach(var inventoryItem in playerItems) { switch(inventoryItem.Item) { case Weapon weapon: // 处理武器逻辑 break; case Armor armor: // 处理护甲逻辑 break; case Potion potion: // 处理药水逻辑 break; } }
不推荐的方案
你之前想到的键值对存储、手动存类型+表ID的方案,会失去EF Core的强类型校验、外键约束、查询优化能力,后期维护成本极高,除非是海量道具的分布式场景,否则完全不需要用。
内容的提问来源于stack exchange,提问作者mummy
相关产品推荐
相关产品推荐

