GORM
存取数组类型数据在
GORM
不支持数组类型变量数据的存取,可以通过GROM
的自定义数据类型实现。
GORM
的自定义类型Scanner
/Valuer
接口 GORM
的自定义的数据类型必须实现Scanner
/Valuer
接口。
(1) Scanner
接口的Scan
方法,是从数据库读取数据到Go变量时需要进行的解析处理,与解码的过程类型。
(2) Valuer
接口的Value
方法,是将Go变量存到数据库时进行编码处理。
虽然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
类型后再存入数据库。定义如下函数进行测试
(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类型
}