英文:
Setting Interface as an attribute having many implementations using GORM
问题
我有一个存储JSON的Postgres数据库,其中一个字段是JSON。表的结构如下:
type Table struct {
ID int
VehicleType string
Vehicle Vehicle `gorm:"type:jsonb"`
// ...
}
现在,Vehicle是一个接口:
type Vehicle interface {
GetEngineModel() string
}
它有很多实现,我将分享其中一个实现 - Car:
type Car struct {
CarEngineModel string //不同实现的属性将不同
}
func (car Car) GetEngineModel() string {
return car.CarEngineModel
}
为了解析特定结构(如Car、Bike等)中的属性,我可以实现所有实现的Scan和Value接口,类似于以下方式:
func (car *Car) Scan(value interface{}) error {
//根据struct表的VehicleType属性使用此Scan实现
b, ok := value.([]byte)
if !ok {
return errors.New("类型断言为[]byte失败")
}
return json.Unmarshal(b, &car)
}
有没有办法根据其他表列告诉我要使用哪个Scan实现,或者是否有其他使用GORM的方法来实现相同的功能?我只想要一个表(通用的JSON类型),所以不想使用多个表来实现多态关联。
英文:
I have a Postgres database which stores JSON as one of its fields. The structure of the table is:
type Table struct {
ID int
VehicleType string
Vehicle Vehicle `gorm:"type:jsonb"`
// ......
}
Now, Vehicle is an interface
type Vehicle interface {
GetEngineModel() string
}
It has many implementation, I will share one of them - Car
type Car struct {
CarEngineModel string //the attributes will be different for different
//implementation
}
func (car Car) GetEngineModel() string {
return car.CarEngineModel
}
In order to parse the attributes in a specific struct i.e. Car, Bike, .., I can implement Scan and Value interface of all the implementations something like this :-
func (car *Car) Scan(value interface{}) error {
//Want to use this implementation of Scan based on VehicleType
//attribute of struct table
b, ok := value.([]byte)
if !ok {
return errors.New("type assertion to []byte failed")
}
*car = json.Unmarshal(b, &car)
}
Is there a way to tell which implementation of Scan to use based on other table columns or an alternate way to do the same using GORM? I only want one table(genetic json type) so don't want to use different tables for different implementations using polymorphic association.
答案1
得分: 3
你可以添加一个单独的字段来保存原始的JSON数据,然后实现gorm
特定的钩子函数来进行数据的编组和解组。
type Table struct {
ID int
VehicleType string
Vehicle Vehicle `gorm:"-"`
// ...
VehicleRaw []byte `gorm:"column:vehicle"`
}
func (t *Table) BeforeSave(tx *gorm.DB) (err error) {
raw, err := json.Marshal(t.Vehicle)
if err != nil {
return err
}
t.VehicleRaw = raw
return nil
}
func (t *Table) AfterFind(tx *gorm.DB) (err error) {
switch t.VehicleType {
case "CAR":
t.Vehicle = &Car{}
case "BIKE":
t.Vehicle = &Bike{}
}
return json.Unmarshal(t.VehicleRaw, t.Vehicle)
}
英文:
You can add a separate field that will hold the raw JSON data and then implement gorm
specific hooks to marshal/unmarshal that data.
type Table struct {
ID int
VehicleType string
Vehicle Vehicle `gorm:"-"`
// ...
VehicleRaw []byte `gorm:"column:vehicle"`
}
func (t *Table) BeforeSave(tx *gorm.DB) (err error) {
raw, err := json.Marshal(t.Vehicle)
if err != nil {
return err
}
t.VehicleRaw = raw
return nil
}
func (t *Table) AfterFind(tx *gorm.DB) (err error) {
switch t.VehicleType {
case "CAR":
t.Vehicle = &Car{}
case "BIKE":
t.Vehicle = &Bike{}
}
return json.Unmarshal(t.VehicleRaw, t.Vehicle)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论