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 } type GameUsers []GameUserfunc (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 } 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 }