Go语言中GORM存取数组/自定义类型数据

GORM存取数组类型数据

GORM不支持数组类型变量数据的存取,可以通过GROM的自定义数据类型实现。

一、GORM的自定义类型

1. Scanner/Valuer接口

GORM的自定义的数据类型必须实现Scanner/Valuer接口。

(1) Scanner接口的Scan方法,是从数据库读取数据到Go变量时需要进行的解析处理,与解码的过程类型。

(2) Valuer接口的Value方法,是将Go变量存到数据库时进行编码处理。

2. 数组变量

​ 虽然GORM不支持数组变量,但是可以通过实现Scanner/Valuer接口,在数据库取/存时进行类似解码/编码的处理,使数组变量成为数据库可支持的变量类型。

(1) 实现Sacnner接口

Scan函数,从数据库读取数据后,对其进行处理,然后获得Go类型的变量。

type Strs []string

func (m *Strs) Scan(val interface{}) error {
	s := val.([]uint8)
	ss := strings.Split(string(s), "|")
	*m = ss
	return nil
}

如上自定义Strs类型,底层类型未字符串数组。Scan函数将读取的val值,按照字符串处理,以"|"为分隔符进行切割,获得字符串数组类型,然后使用指针赋值。

(2) 实现Valuer接口

Value函数,将数据存到数据库时,对数据进行处理,获得数据库支持的类型。

func (m Strs) Value() (driver.Value, error) {
	str := strings.Join(m, "|")
	return str, nil
}

如上将Strs存入数据库前,将数组内的字符串用"|"拼接,获得数据库支持的string类型后再存入数据库。

3. 测试

定义如下函数进行测试

(1) 模型变量

type User struct {
	ID uint `gorm:"primary_key"`
	Name string
	Pics Strs `gorm:"type:longtext"` // 自定义的数组类型,在数据库中存为长文本类型
}

​ (2) Service函数

func SaveUser(user User) error {
	var err error
	err = db.Save(&user).Error
	return err
}

func GetUser(name string) (User, error) {
	var user User
	err := db.First(&user, "name = ?", name).Error
	return user, err
}

​ (3) testService函数

func TestSaveUser() {
 user := User{
 Name: "Jason",
 Pics: Strs{
 "123124",
 "gtsrbxrzsfcv",
 },
 }
 err := SaveUser(user)
 if err != nil {
 log.Panicln("保存失败!", err)
 } else {
 log.Println("保存成功!")
 }
}

func TestGetUser() {
 user, err := GetUser("Jason")
 if err != nil {
 log.Panicln("获取失败!", err)
 } else {
 log.Println("获取成功!", user)
 }
}

​ (4) 运行结果

2022/07/30 18:18:41 保存成功!
2022/07/30 18:18:41 获取成功! {3 Jason [123124 gtsrbxrzsfcv]}

在数据库存储中体现为:

mysql> select *from users;
+----+-------+---------------------+
| id | name | pics |
+----+-------+---------------------+
| 3 | Jason | 123124|gtsrbxrzsfcv |
+----+-------+---------------------+
1 row in set (0.00 sec)

二、实际生产

上面的例子中展示了Scanner/Valuer接口的简单使用,实际生产中将数组类型转换为json字符串进行保存,下面展示一个完整的例子,以一个User拥有一张包含信息的银行卡为例(当然可以通过一对一关联4444实现)。

(1) 实现自定义类型

type User struct {
 ID uint `gorm:"primary_key"`
 Name string
 Cards Card `gorm:"json"`
}

type Card struct { // 指定json的Tag。
 Type int `json:"type"`
 Account string `json:"account"`
 Password string `json:"password"`
}

// Scan 解码json字符串
func (card *Card) Scan(val interface{}) error {
 b, _ := val.([]byte)
 return json.Unmarshal(b, card)
}

// Value 编码json
func (card Card) Value() (value driver.Value, err error) {
	return json.Marshal(card)
}

​ (2) 数据表模型

type User struct {
 ID uint `gorm:"primary_key"`
 Name string
 Cards Card `gorm:"json"` // 指定为json类型
}

​总结

作者:Go~Go~Go~原文地址:https://blog.csdn.net/js010111/article/details/126076320

%s 个评论

要回复文章请先登录注册