GOM ORM在GO中 - 多态关联 - 如何惯用亚型访问
我正在使用 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 中提取子类型的内容。我认为这很难正确输入提示,但也许存在某种反射方法可以让我提取公共属性?
I'm using Gorm ORM and have a polymorphic association set up between Items and the subtypes Weapon/Armor/Jewelry.
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
}
I want to be able to have a list of item names (e.g. for an inventory listing). Ultimately I want to be able to get out any other common attributes that are shared between all the subtypes (like maybe a weight, cost, etc).
I'm not happy with the "solution" that I have and I think that there has to be a better way to do this. Could anybody with more experience than me show me a pattern that accomplishes this?
My idea was to have a nested function that is able to build up the DTO that has the common attributes.
But I will need a switch statement for every item type that I want to support.
// 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"}
}
}
Is there a more general way to do this? I can't find anything in the Gorm documentation that lets you magically pull the subtype from the Item. I think this would be hard to type hint properly, but maybe some sort of reflection method exists that would let me pull out common attributes?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是一个相当晚的回复,但我建议您也许应该再看看您的表关系。从数据库设计的角度来看,如果您在多个表上共享属性,那么可能值得将这些属性提取到另一个表并让每个原始表引用该表。简单的例子:
好的,这是一个简单的多态示例,其中汽车和自行车都是车辆,所以我们可以只使用 go 的结构嵌入语法。但如果您考虑项目,也许它们总是具有重量、成本等。您可以简单地将这些属性移至您的 Item 模型中,而不是将它们包含在子类型中。或者,您可以在结构上定义方法(不是 100% Go 用来描述这个概念的语言),以便您可以利用接口:
显然,后面的示例对查询没有帮助,只有查询后才能使用这个
GetProperties
函数。因此,您可以查询库存中所有内容的完整列表,然后对该列表中的每个项目调用GetProperties
(或类似)函数This is a pretty late response, but I would offer that perhaps you should take another look at your table relationship. From a database design perspective, if you have shared properties on multiple tables, then it may be worth extracting those properties out to another table and having each of the original tables reference that table. Simple example:
Okay, so that's a simple polymorphic example where car and bike are both vehicles, so we can just use go's struct embedding syntax. But if you consider items, perhaps they always have a weight, a cost, etc. You could simply move those attributes into your Item model instead of containing them in your sub types. Alternatively, you can define methods (not 100% of the language Go uses to describe this concept) on your structs so that you can utilize an interface:
Obviously, this later example doesn't help with querying, only after querying are you able to use this
GetProperties
function. So you could query for the full list of everything in the inventory, then call the yourGetProperties
(or similar) function on each item in that list