DevOps运维技术栈

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
}

总结

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

退出移动版