golang-gorm库不支持[]string类型问题的解决方法

golang-gorm库不支持[]string类型问题的解决方法,第1张

备注: gorm自定义json格式


文章目录 遇到问题分析原因解决方案step 1step 2


遇到问题

在使用gorm包定义的数据库的结构如下:

type SystemParameter struct {
   GlobalSslEnable            bool      `json:"globalSslEnable,omitempty"`
   GlobalSslVisitedHosts      []string	`json:"globalSslVisitedHosts,omitempty"`
   UserInfoInterfaceURL       string    `json:"userInfoInterfaceURL,omitempty"`
}

对数据库创建mysql数据的时候报错:(sql: converting argument $1 type: unsupported type []string, a slice of string)

分析原因

mysql中不支持[]string 类型的数据,不可以直接在结构体中定义[]string 类型。

mysql中支持的数据结构类型有如下几种:

数值类型:TINYINT、SMALLINT、MEDIUMINT、INT或INTEGER、BIGINT、FLOAT、DOUBLE、DECIMAL;

日期和时间类型:DATE、TIME、YEAR、DATETIME、TIMESTAMP;

字符串类型:CHAR、VARCHAR、TINYBLOB、TINYTEXT、BLOB、TEXT、MEDIUMBLOB、MEDIUMTEXT、LONGBLOB、LONGTEXT;

因此mysql中并不支持[]string 类型的数据,不能直接在结构体中直接定义,为了能够在数据库中存储[]string 类型的数据,需要讲结构体中这个类型的数据进行封装,转换成为mysql支持的数据类型。

解决方案

基于gorm 库的特性,可以通过自定义JSON类型将数据传入,因此解决步骤一共分为两步:

step 1:将[]string类型编码为JSON类型数据;step 2:自定义JSON类型数据,使得gorm可以支持,可以参考GORM-自定义数据类型; step 1

首先将结构体中数据类型定义改为一个新的自定义类型,NullGlobalSslVisitedHosts用于判断GlobalSslVisitedHosts是否为空。

// 修改types.go
type SystemParameter struct {
   GlobalSslEnable            bool      `json:"globalSslEnable,omitempty"`
   GlobalSslVisitedHosts      NullGlobalSslVisitedHosts	`json:"globalSslVisitedHosts,omitempty"`
   UserInfoInterfaceURL       string    `json:"userInfoInterfaceURL,omitempty"`
}

type NullGlobalSslVisitedHosts struct {
	GlobalSslVisitedHosts GlobalSslVisitedHosts
	Valid                 bool
}

type GlobalSslVisitedHosts []string

// GormDataType return the gorm data type
func (GlobalSslVisitedHosts) GormDataType() string {
	return "json"
}

gorm的依赖库中(地址为:gorm.io/gorm/schema/field.go)修改,增加上面刚定义的函数

// 修改gorm.io/gorm/schema/field.go

if dataTyper, ok := fieldValue.Interface().(GormDataTypeInterface); ok {
		field.DataType = DataType(dataTyper.GormDataType())
	}

gorm的依赖库中(地址为:gorm.io/gorm/schema/interfaces.go) 增加定义的接口

// 修改gorm.io/gorm/schema/interfaces.go

type GormDataTypeInterface interface {
   GormDataType() string
}
step 2

自定义一个JSON类型,可以参考GORM-自定义数据类型

// 修改types.go

// Scan implements the Scanner interface.
func (n *NullGlobalSslVisitedHosts) Scan(value interface{}) error {
   if value == nil {

      n.GlobalSslVisitedHosts, n.Valid = GlobalSslVisitedHosts{}, false

      return nil
   }
   n.Valid = true

   var t GlobalSslVisitedHosts
   err := t.Scan(value)
   if err != nil {
      return err
   }
   n.GlobalSslVisitedHosts, n.Valid = t, true

   return nil
}

// Value implements the driver Valuer interface.
func (n NullGlobalSslVisitedHosts) Value() (driver.Value, error) {
   if !n.Valid {
      return nil, nil
   }

   return n.GlobalSslVisitedHosts.Value()

}

func (i *GlobalSslVisitedHosts) Scan(value interface{}) error {
   bytesValue, ok := value.([]byte)
   if !ok {
      return errors.New(fmt.Sprint("Failed to unmarshal GlobalSslVisitedHosts value:", value))
   }
   return json.Unmarshal(bytesValue, i)
}

// Value return json value, implement driver.Valuer interface
func (i GlobalSslVisitedHosts) Value() (driver.Value, error) {
   return json.Marshal(i)
}

func (v NullGlobalSslVisitedHosts) MarshalJSON() ([]byte, error) {
	if v.Valid {
		return json.Marshal(v.GlobalSslVisitedHosts)
	} else {
		return json.Marshal(nil)
	}
}

func (v *NullGlobalSslVisitedHosts) UnmarshalJSON(data []byte) error {
	// Unmarshalling into a pointer will let us detect null
	var x *GlobalSslVisitedHosts
	if err := json.Unmarshal(data, &x); err != nil {
		return err
	}
	if x != nil {
		v.Valid = true
		v.GlobalSslVisitedHosts = *x
	} else {
		v.Valid = false
	}
	return nil
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/995144.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存