前言
上一篇golang-gorm库不支持[]string类型问题的解决方法,解决了一个gorm库中正确识别复杂结构体类型的问题,这里根据官方文档简单实现两种常见自定义类型的数据。
首先给出gorm官方文档的地址,遇到相关问题,最好的解决方法始终是查看官方文档,并尝试其中的标准解决方案。
[]string类型
定义需要传入数据库的结构体 RateLimitPolicy
,其中两种数据类型,在下面分别定义:
type RateLimitPolicy struct {
AllowedIpRange AllowedIpRange `json:"allowedIpRange,omitempty"`
AllowedIps AllowedIps `json:"allowedIps,omitempty"`
}
定义了AllowedIps
为[]string
:
type AllowedIps []string
此种类型在gorm中不可以直接识别,需要自定义数据类型。
func (a *AllowedIps) 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, a)
}
// Value return json value, implement driver.Valuer interface
func (a AllowedIps) Value() (driver.Value, error) {
return json.Marshal(a)
}
通过Scan()
与Value()
两个函数完成自定义。
struct{}类型
定义需要传入数据库的结构体 RateLimitPolicy
,其中两种数据类型,在下面分别定义:
type RateLimitPolicy struct {
AllowedIpRange AllowedIpRange `json:"allowedIpRange,omitempty"`
AllowedIps AllowedIps `json:"allowedIps,omitempty"`
}
定义了AllowedIpRange
为struct{}
:
type AllowedIpRange struct {
Begin gwtype.String `json:"begin,omitempty"`
End gwtype.String `json:"end,omitempty"`
}
此种类型在gorm中不可以直接识别,需要自定义数据类型。
func (ar *AllowedIpRange) 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, ar)
}
// Value return json value, implement driver.Valuer interface
func (ar AllowedIpRange) Value() (driver.Value, error) {
return json.Marshal(ar)
}
通过Scan()
与Value()
两个函数完成自定义。
附录:官方文档中自定义数据类型
GORM 提供了少量接口,使用户能够为 GORM 定义支持的数据类型,这里以 json 为例
实现自定义数据类型
Scanner / Valuer
自定义的数据类型必须实现 Scanner 和 Valuer 接口,以便让 GORM 知道如何将该类型接收、保存到数据库
例如:
type JSON json.RawMessage
// 实现 sql.Scanner 接口,Scan 将 value 扫描至 Jsonb
func (j *JSON) Scan(value interface{}) error {
bytes, ok := value.([]byte)
if !ok {
return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value))
}
result := json.RawMessage{}
err := json.Unmarshal(bytes, &result)
*j = JSON(result)
return err
}
// 实现 driver.Valuer 接口,Value 返回 json value
func (j JSON) Value() (driver.Value, error) {
if len(j) == 0 {
return nil, nil
}
return json.RawMessage(j).MarshalJSON()
}