在使用 GORM 时,存取数组或自定义类型的数据需要一些额外的处理。GORM 本身并不直接支持数组或复杂类型的字段,但可以通过以下几种方式实现:
1. 使用 gorm:"serializer"
标签
GORM 提供了 serializer
标签,可以将复杂类型序列化为 JSON 或其他格式存储在数据库中。
package main
import (
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type User struct {
gorm.Model
Name string
Tags []string `gorm:"serializer:json"`
}
func main() {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
db.AutoMigrate(&User{})
// 创建用户
user := User{Name: "John", Tags: []string{"golang", "backend", "devops"}}
db.Create(&user)
// 查询用户
var result User
db.First(&result, "name = ?", "John")
println(result.Tags[0]) // 输出: golang
}
2. 自定义数据类型
你可以通过实现 Scanner
和 Valuer
接口来定义自定义数据类型。
package main
import (
"database/sql/driver"
"encoding/json"
"errors"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type StringArray []string
func (s *StringArray) Scan(value interface{}) error {
bytes, ok := value.([]byte)
if !ok {
return errors.New("failed to scan StringArray")
}
return json.Unmarshal(bytes, s)
}
func (s StringArray) Value() (driver.Value, error) {
return json.Marshal(s)
}
type User struct {
gorm.Model
Name string
Tags StringArray
}
func main() {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
db.AutoMigrate(&User{})
// 创建用户
user := User{Name: "John", Tags: []string{"golang", "backend", "devops"}}
db.Create(&user)
// 查询用户
var result User
db.First(&result, "name = ?", "John")
println(result.Tags[0]) // 输出: golang
}
3. 使用关联表
如果数组或自定义类型的数据比较复杂,可以考虑使用关联表来存储。
package main
import (
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type User struct {
gorm.Model
Name string
Tags []Tag `gorm:"many2many:user_tags;"`
}
type Tag struct {
gorm.Model
Name string
}
func main() {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
db.AutoMigrate(&User{}, &Tag{})
// 创建用户和标签
tags := []Tag{{Name: "golang"}, {Name: "backend"}, {Name: "devops"}}
user := User{Name: "John", Tags: tags}
db.Create(&user)
// 查询用户
var result User
db.Preload("Tags").First(&result, "name = ?", "John")
println(result.Tags[0].Name) // 输出: golang
}
总结
gorm:"serializer:json"
:适用于简单的数组或自定义类型。- 自定义数据类型:适用于需要更复杂逻辑的场景。
- 关联表:适用于复杂的数据结构或需要查询的场景。
根据你的需求选择合适的方式来实现数组或自定义类型数据的存取。