Go中的Gorm-ORM-多态关联-如何惯用地访问子类型



我正在使用Gorm ORM,并在物品和子类型武器/盔甲/珠宝之间建立了多态关联。

type Item struct {
models.Model
// see https://gorm.io/docs/has_many.html#Polymorphism-Association
SubID     string
SubType   string
CraftedBy string
}
type ItemWeaponSubtype struct {
models.Model
Items           []Item `gorm:"polymorphic:Sub;polymorphicValue:weapon"`
Name            string
Quality         string `gorm:"type:varchar(20)""`
Material        string `gorm:"type:varchar(20)""`
EquipmentSlotId string
DamageBonuses
}

我希望能够有一个物品名称列表(例如,库存清单(。最终,我希望能够获得所有子类型之间共享的任何其他公共属性(比如权重、成本等(。

我对";解决方案";我有,我认为必须有更好的方法来做到这一点。有谁比我更有经验,能给我展示一种实现这一点的模式吗?

我的想法是有一个嵌套函数,它能够构建具有公共属性的DTO。

但是,对于我想要支持的每一种项目类型,我都需要一个switch语句。

// ItemCommonDetails contains fields that all subtypes have and is useful for displaying inventory lists etc
type ItemCommonDetails struct {
Name string
}
func (ir *ItemRepository) GetItemCommonDetailsFromId(itemId string) (ItemCommonDetails, error) {
var item models.Item
result := ir.db.First(&item, "id = ?", itemId)
if 0 == result.RowsAffected {
return ItemCommonDetails{Name: "Err!"}, &common_dto.StatusError{Code: http.StatusNotFound, Message: "Item [" + itemId + "] not found"}
}
defineReturn := func(result *gorm.DB, name string) (ItemCommonDetails, error) {
if result.RowsAffected == 0 {
return ItemCommonDetails{Name: "Err!"}, &common_dto.StatusError{Code: http.StatusNotFound, Message: "Item [" + itemId + "] not found"}
}
return ItemCommonDetails{Name: name}, nil
}
switch item.SubType {
case "weapon":
var weapon models.ItemWeaponSubtype
result := ir.db.First(&weapon, "id = ?", item.SubID)
return defineReturn(result, weapon.Name)
case "armor":
var armor models.ItemArmorSubtype
result := ir.db.First(&armor, "id = ?", item.SubID)
return defineReturn(result, armor.Name)
case "jewelry":
var jewelry models.ItemJewelrySubtype
result := ir.db.First(&jewelry, "id = ?", item.SubID)
return defineReturn(result, jewelry.Name)
default:
return ItemCommonDetails{Name: "Err!"}, &common_dto.StatusError{Code: http.StatusNotFound, Message: "Item [" + itemId + "] not found"}
}
}

有更通用的方法吗?我在Gorm文档中找不到任何可以让您神奇地从Item中提取子类型的东西。我认为这很难正确地键入提示,但也许存在某种反射方法,可以让我提取常见的属性?

这是一个相当晚的响应,但我建议您也许应该重新审视一下您的表关系。从数据库设计的角度来看,如果您在多个表上有共享属性,那么可能值得将这些属性提取到另一个表中,并让每个原始表引用该表。简单示例:

// originally, we have Car and Bike sharing the attributes NumWheels and Owner
type Car struct {
NumWheels int
Owner string
Mileage int
Make string
Model string
}
type Bike struct {
NumWheels int
Owner string
Color string
Brand string
}
// one refactoring later...
type Vehicle struct {
NumWheels int
Owner string
}
type Car struct {
Vehicle
Mileage int
Make string
Model string
}
type Bike struct {
Vehicle
Color string
Brand string
}

好吧,这是一个简单的多态示例,其中汽车和自行车都是车辆,所以我们可以使用go的结构嵌入语法。但是,如果你考虑项目,也许它们总是有权重、成本等。你可以简单地将这些属性移动到项目模型中,而不是将它们包含在子类型中。或者,你可以在你的结构上定义方法(而不是Go用来描述这个概念的100%语言(,这样你就可以使用一个接口:

type Itemlike interface {
GetWeight() int
GetCost() int
// etc
}
func GetProperties(i *Itemlike) map[string]int {
res := map[string]int{"weight": i.GetWeight(), "cost": i.GetCost()}
return res
}

显然,后面的示例对查询没有帮助,只有在查询之后才能使用此GetProperties函数。因此,您可以查询库存中所有物品的完整列表,然后对该列表中的每个物品调用GetProperties(或类似的(函数

最新更新