gorm实现Scanner/Valuer接口存取数组类型和自定义类型数据

在使用 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":适用于简单的数组或自定义类型。
  • 自定义数据类型:适用于需要更复杂逻辑的场景。
  • 关联表:适用于复杂的数据结构或需要查询的场景。

根据你的需求选择合适的方式来实现数组或自定义类型数据的存取。

声明: 本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

给TA打赏
共{{data.count}}人
人已打赏
Golang

实现go标准库sort的方法对自定义结构体进行排序

2025-2-10 11:19:35

Golang

golang通过websocket将Jenkins构建日志实时输出到浏览器

2025-2-11 16:46:00

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索