Go语言中GORM存取数组/自定义类型数据
Go~Go~Go~ 人气:0GORM存取数组类型数据
在
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类型 }
总结
加载全部内容