高级主题

Serializer

qianmoQqianmoQ· 更新于 2026-09-23· 阅读 7 分钟· 0 次阅读

登录后可跨设备保存划线和私人笔记登录

Serializer 是一个可扩展的接口,允许自定义数据与数据库之间的序列化和反序列化方式。

GORM 提供了一些默认的序列化器:json、gob、unixtime,以下是其使用方法的简单示例。

type User struct {
  Name        []byte                 `gorm:"serializer:json"`
  Roles       Roles                  `gorm:"serializer:json"`
  Contracts   map[string]interface{} `gorm:"serializer:json"`
  JobInfo     Job                    `gorm:"type:bytes;serializer:gob"`
  CreatedTime int64                  `gorm:"serializer:unixtime;type:time"` 
}

type Roles []string

type Job struct {
  Title    string
  Location string
  IsIntern bool
}

createdAt := time.Date(2020, 1, 1, 0, 8, 0, 0, time.UTC)
data := User{
  Name:        []byte("jinzhu"),
  Roles:       []string{"admin", "owner"},
  Contracts:   map[string]interface{}{"name": "jinzhu", "age": 10},
  CreatedTime: createdAt.Unix(),
  JobInfo: Job{
    Title:    "Developer",
    Location: "NY",
    IsIntern: false,
  },
}

DB.Create(&data)



var result User
DB.First(&result, "id = ?", data.ID)






DB.Where(User{Name: []byte("jinzhu")}).Take(&result)

注册序列化器

序列化器需要实现数据的序列化和反序列化方式,因此需要实现以下接口:

import "gorm.io/gorm/schema"

type SerializerInterface interface {
  Scan(ctx context.Context, field *schema.Field, dst reflect.Value, dbValue interface{}) error
  SerializerValuerInterface
}

type SerializerValuerInterface interface {
  Value(ctx context.Context, field *schema.Field, dst reflect.Value, fieldValue interface{}) (interface{}, error)
}

例如,默认的 JSONSerializer 实现如下:


type JSONSerializer struct {
}


func (JSONSerializer) Scan(ctx context.Context, field *schema.Field, dst reflect.Value, dbValue interface{}) (err error) {
  fieldValue := reflect.New(field.FieldType)

  if dbValue != nil {
    var bytes []byte
    switch v := dbValue.(type) {
    case []byte:
      bytes = v
    case string:
      bytes = []byte(v)
    default:
      return fmt.Errorf("failed to unmarshal JSONB value: %#v", dbValue)
    }

    err = json.Unmarshal(bytes, fieldValue.Interface())
  }

  field.ReflectValueOf(ctx, dst).Set(fieldValue.Elem())
  return
}


func (JSONSerializer) Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (interface{}, error) {
  return json.Marshal(fieldValue)
}

通过以下代码注册:

schema.RegisterSerializer("json", JSONSerializer{})

注册序列化器后,可以通过 serializer 标签使用它,例如:

type User struct {
  Name []byte `gorm:"serializer:json"`
}

自定义序列化器类型

你可以通过标签使用已注册的序列化器,也可以创建一个实现上述 SerializerInterface 的自定义结构体,并直接将其用作字段类型,例如:

type EncryptedString string




func (es *EncryptedString) Scan(ctx context.Context, field *schema.Field, dst reflect.Value, dbValue interface{}) (err error) {
  switch value := dbValue.(type) {
  case []byte:
    *es = EncryptedString(bytes.TrimPrefix(value, []byte("hello")))
  case string:
    *es = EncryptedString(strings.TrimPrefix(value, "hello"))
  default:
    return fmt.Errorf("unsupported data %#v", dbValue)
  }
  return nil
}




func (es EncryptedString) Value(ctx context.Context, field *schema.Field, dst reflect.Value, fieldValue interface{}) (interface{}, error) {
  return "hello" + string(es), nil
}

type User struct {
  gorm.Model
  Password EncryptedString
}

data := User{
  Password: EncryptedString("pass"),
}

DB.Create(&data)


var result User
DB.First(&result, "id = ?", data.ID)




DB.Where(User{Password: EncryptedString("pass")}).Take(&result)

评论

登录后参与评论

正在加载评论…