Gorm-JSON格式问题

概述

在使用Gorm的时候,常常会使用JSON格式,但是JSON在Gorm的ORM中表达有着许多解析问题

问题描述

  • []也是作为JSON格式的一种,里面可以切套object对象,但是实际上我们可以看作一个数组,这种时候
  • 当我们使用

步骤

建立表格

type User struct {
gorm.Model
Name string
Age int
GameUser []GameUser `json:"game_user" gorm:"type:json"`
}
type GameUser struct {
ID int
Name string
PassWord string
}

func main() {
dsn := "root:123456@tcp(10.0.0.197:3303)/joohwan_dev?parseTime=true"

mysqlDb, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic(err)
}
mysqlDb.AutoMigrate(&User{})

}

成功获得了我们需要的JOSN的表格

插入数据

func insert(db *gorm.DB) {
user := User{
Name: "user1",
Age: 18,
GameUser: []GameUser{{ID: 1, Name: "gameuser1"}, {ID: 2, Name: "gameuser2"}},
}
if err := db.Create(&user).Error; err != nil {
panic(err)
}
}

当我们尝试利用ORM插入数据的时候,“诡异”的事情出现了,居然报错!?

  • 解读一下这个错误,大概意思是序列化失败了

  • INSERT INTO users(created_at, updated_at, deleted_at, name, age, game_user) VALUES ( '2024-08-30 06:38:01.857', '2024-08-30 06:38:01.857', NULL, 'user1', 18,( '{1 gameuser1 }', '{1 gameuser1 }' )),看SQL其实也能发现,居然是俩行的而不是[]形式,而且没有JSON格式

解决问题

我们只需要实现Gorm中Value方法,这个方法是我们转换为JSON到数据库中

type User struct {
gorm.Model
Name string
Age int
GameUser GameUsers `json:"game_user" gorm:"type:json"`
}
type GameUser struct {
ID int
Name string
PassWord string
}
// 主要是以[]为开头,解决,不然重写Value方法依旧是没有
type GameUsers []GameUser
// 不能使用指针接收者,不然不生效
func (e GameUsers) Value() (driver.Value, error) {
str, err := json.Marshal(e)
if err != nil {
return nil, err
}
return string(str), nil
}
设置Gorm为DeBug()级别,观察SQL,我们也会发现,现在的SQL也是我们期望的
INSERT INTO `users` (`created_at`,`updated_at`,`deleted_at`,`name`,`age`,`game_user`) VALUES ('2024-08-30 06:40:58.936','2024-08-30 06:40:58.936',NULL,'user1',18,'[{"ID":1,"Name":"gameuser1","PassWord":""},{"ID":1,"Name":"gameuser1","PassWord":""}]')

查询数据

既然插入不行,那我们试试查询呢

func getById(db *gorm.DB) User {
user := User{}
if err := db.Debug().First(&user).Where("id", 1).Error; err != nil {
panic(err)
}
return user
}

  • 非常好,依旧是解析失败了

解决问题

Scan 方式是Gorm中另外一个JSON解析的方法,这是在数据库映射到ORM到时候,执行的方法,所以我们重写一下,这个方法,发现我们可以成功解析数据库的ORM对象了

func (e *GameUsers) Scan(value interface{}) error {
if value == nil {
return nil
}

// Unmarshal the json.RawMessage into an InstanceData struct
switch v := value.(type) {
case []byte:
if err := json.Unmarshal(v, e); err != nil {
return err
}
case string:
if err := json.Unmarshal([]byte(v), e); err != nil {
return err
}
default:
if err := json.Unmarshal(v.([]byte), e); err != nil {
return err
}
}
return nil
}