将接口设置为具有多个实现的属性,使用GORM。

huangapple go评论82阅读模式
英文:

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)
}

huangapple
  • 本文由 发表于 2021年7月19日 15:49:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/68436921.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定