📦GORMv1.25.6
🏆 自定义数据
⭐️ 在有些时候,数据库内单单存储基本数据类型往往不够,可能需要存储 json
这种类型
🍅 实习自定义数据类型
🌟 Scanner / Valuer
自定义的数据类型必须实现 Scanner 和 Valuer 接口,以便让 GORM 知道如何将该类型接收、保存到数据库
结构体这个类型就和json非常相似,可以直接通过 json
标签来指定是 json
类型的,然后后面接的是在 json
中存储的字段
type Task struct {
Status string `json:"status"`
Title string `json:"title"`
Context int `json:"context"`
}
// Scan 从数据库中读取出来
func (i *Task) Scan(value interface{}) error {
//存储的时候使用断言转换为byte
bytes, ok := value.([]byte)
if !ok {
return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value))
}
//使用字符串存入
err := json.Unmarshal(bytes, i)
return err
}
// Value 存入数据库
func (i Task) Value() (driver.Value, error) {
//将字符串转换为json读出
return json.Marshal(i)
}
type User struct {
gorm.Model
Name string
Password string
Task Task `gorm:"type:string;"`
}
创建对象并插入
func main() {
// 连接数据库
db, err := untils.Dbuntils()
if err != nil {
println("连接数据库失败", err.Error())
}
createTablesError := db.AutoMigrate(&User{})
if createTablesError != nil {
fmt.Println("创建表失败", createTablesError.Error())
}
u := &User{
Name: "zhangsan",
Password: "123456",
Task: Task{
Status: "1",
Title: "title",
Context: "学习Gorm",
},
}
db.Debug().Create(u)
}
执行完成查看数据语句
INSERT INTO `gormuser` (`created_at`,`updated_at`,`deleted_a
t`,`name`,`password`,`task`) VALUES ('2024-07-03 20:34:22.14','2024-07-03 20:34:
22.14',NULL,'zhangsan','123456','{"status":"1","title":"title","context":"学习Go
rm"}') RETURNING `id`
MariaDB [gorm]> select * from gormuser;
+----+-------------------------+-------------------------+------------+----------+----------+-------------------------------------------------------+
| id | created_at | updated_at | deleted_at | name | password | task |
+----+-------------------------+-------------------------+------------+----------+----------+-------------------------------------------------------+
| 1 | 2024-07-03 20:34:22.140 | 2024-07-03 20:34:22.140 | NULL | zhangsan | 123456 | {"status":"1","title":"title","context":"学习Gorm"} |
+----+-------------------------+-------------------------+------------+----------+----------+-------------------------------------------------------+
1 row in set (0.002 sec)
MariaDB [gorm]>
🍅 GormDataTypeInterface
GORM 会从 type
标签 中读取字段的数据库类型,如果找不到,则会检查该结构体是否实现了 GormDBDataTypeInterface
或 GormDataTypeInterface
接口,然后使用接口返回值作为数据类型
type GormDataTypeInterface interface {
GormDataType() string
}
type GormDBDataTypeInterface interface {
GormDBDataType(*gorm.DB, *schema.Field) string
}
GormDataType
的结果用于生成通用数据类型,也可以通过 schema.Field
的 DataType
字段得到。这在 编写插件 或者 hook 时可能会有用,例如:
func (JSON) GormDataType() string {
return "json"
}
type User struct {
Attrs JSON
}
func (user User) BeforeCreate(tx *gorm.DB) {
field := tx.Statement.Schema.LookUpField("Attrs")
if field.DataType == "json" {
// 做点什么...
}
}
在迁移时,GormDBDataType
通常会为当前驱动返回恰当的数据类型,例如:
func (JSON) GormDBDataType(db *gorm.DB, field *schema.Field) string {
// 使用 field.Tag、field.TagSettings 获取字段的 tag
// 查看 https://github.com/go-gorm/gorm/blob/master/schema/field.go 获取全部的选项
// 根据不同的数据库驱动返回不同的数据类型
switch db.Dialector.Name() {
case "mysql", "sqlite":
return "JSON"
case "postgres":
return "JSONB"
}
return ""
}
如果 struct 没有实现 GormDBDataTypeInterface
或 GormDataTypeInterface
接口,GORM 会根据 struct 第一个字段推测其数据类型,例如:会为 NullString
使用 string
type NullString struct {
String string // 使用第一个字段的数据类型
Valid bool
}
type User struct {
Name NullString // 数据类型会是 string
}