GORM 是 Go 语言中最流行的 ORM 之一,它简化了数据库操作,提升了开发效率。然而,在某些情况下,标准的数据类型无法满足复杂业务需求。
例如,**如何将 Go 中的结构体、切片、JSON 等类型映射到数据库字段?**如何方便地进行序列化和反序列化?
为了解决这些问题,GORM 提供了 datatypes (gorm.io/datatypes) 扩展库,旨在简化 Go 语言中复杂数据类型与数据库字段之间的映射和操作。它提供了一系列预定义的数据类型,方便开发者直接使用,而无需自己编写繁琐的转换代码。
datatypes.JSON
datatypes.JSON 允许在数据库中存储 JSON 格式的数据。
定义字段类型 datatypes.JSON :
go
import "gorm.io/datatypes"
type User struct {
ID int
Name string
Conf datatypes.JSON // 对应数据库JSON类型
}
func (u User) TableName() string {
return "test_json_user"
}
插入 JSON 数据:
go
user := User{
Name: "Alice",
Conf: datatypes.JSON(`{"theme": "dark", "lang": "en"}`),
}
db.Create(&user)
// INSERT INTO `test_json_user` (`name`,`conf`) VALUES ('Alice',CAST('{"theme": "dark", "lang": "en"}' AS JSON))
检查 JSON 键对应的值是否等于指定值:
查找 conf 字段中 theme 键的值是否为 "dark"。
go
var result User
db.Where(datatypes.JSONQuery("conf").Equals("dark", "theme")).Find(&result)
// SELECT * FROM `test_json_user` WHERE JSON_EXTRACT(`conf`,'$.theme') = 'dark'
查询 JSON 数据:
可以使用 json.Unmarshal 解析 JSON 结构。
go
type Conf struct {
Theme string `json:"theme"`
Lang string `json:"lang"`
}
var result User
db.Where("name = ?", "Alice").Find(&result)
var conf Conf
json.Unmarshal(result.Conf, &conf)
fmt.Printf("%+v\n", conf)
// {Theme:dark Lang:en}
datatypes.JSONTypeT
与使用 datatypes.JSON 需手动解析数据到结构体不同,使用 datatypes.JSONTypeT,查询时它可以自动将 JSON 数据映射到 Go 结构体。
定义字段类型 datatypes.JSONTypeT :
go
type User struct {
ID int
Name string
Conf datatypes.JSONType[Conf]// 对应数据库JSON类型
}
type Conf struct {
Theme string `json:"theme"`
Lang string `json:"lang"`
}
插入 JSON 数据:
go
conf := Conf{Theme: "dark", Lang: "en"}
user := User{
Name: "Alice",
Conf: datatypes.NewJSONType(conf),
}
db.Create(&user)
查询 JSON 数据:
查询时自动将 JSON 数据映射到 Go 结构体。使用 result.Conf.Data() 可以直接访问 JSON 数据中的字段。
go
var result User
db.Where("name = ?", "Alice").Find(&result)
fmt.Printf("%+v\n", result.Conf.Data()) // {Theme:dark Lang:en}
fmt.Println(result.Conf.Data().Theme) // dark
fmt.Println(result.Conf.Data().Lang) // en
datatypes.JSONSliceT
datatypes.JSONSlice 可以方便地存储 JSON 数组。查询时自动解析 JSON 数组。
定义字段类型 datatypes.JSONSliceT :
go
type User struct {
ID int
Name string
Conf datatypes.JSONSlice[Conf] // 对应数据库JSON类型
}
type Conf struct {
Theme string `json:"theme"`
Lang string `json:"lang"`
}
插入 JSON 数据:
go
conf := []Conf{
{Theme: "dark", Lang: "en"},
{Theme: "light", Lang: "zh"},
}
user := User{
Name: "Alice",
Conf: datatypes.NewJSONSlice(conf),
}
db.Create(&user)
// INSERT INTO `test_json_user` (`name`,`conf`) VALUES ('Alice',CAST('[{"theme":"dark","lang":"en"},{"theme":"light","lang":"zh"}]' AS JSON))
/* 另一个例子储存int数组
type User struct {
ID int
Name string
Conf datatypes.JSONSlice[int] // 对应数据库JSON类型
}
conf := []int{1, 2, 3, 4}
user := User{
Name: "Alice",
Conf: datatypes.NewJSONSlice(conf),
}
db.Create(&user)*/
查询 JSON 数据:
go
var result User
db.Where("name = ?", "Alice").Find(&result)
fmt.Printf("%+v\n", result.Conf) // [{Theme:dark Lang:en} {Theme:light Lang:zh}]
fmt.Println(result.Conf[0].Theme) // dark
fmt.Println(result.Conf[0].Lang) // en
通过这些示例,我们可以看到 gorm.io/datatypes 的强大之处:它简化了复杂数据类型的处理,让开发者可以更专注于业务逻辑。了解更多数据类型和使用方法请阅读官方文档。
References