字段定义

字段是模型的基本组成。GORM 支持丰富的数据类型,也允许自定义数据库字段类型。这一章详细介绍各种字段的定义方式。

基本数据类型

整数类型

type User struct {
    ID        uint      // bigint unsigned, 主键
    Age       int       // int
    Score     int32     // int
    Balance   int64     // bigint
    Followers uint32    // int unsigned
    Views     uint64    // bigint unsigned
}

浮点类型

type Product struct {
    Price    float32   // float
    Weight   float64   // double
}

字符串类型

type User struct {
    Name     string    // varchar(191)
    Bio      string    // longtext
    Avatar   string    // varchar(191)
}

默认 string 映射为 varchar(191)。191 是 MySQL utf8mb4 索引长度限制。

布尔类型

type User struct {
    Active   bool      // tinyint(1)
    Verified bool
}

时间类型

type Event struct {
    CreatedAt time.Time  // datetime
    StartTime time.Time
    EndTime   time.Time
}

自定义字段类型

type 标签指定数据库类型:

type User struct {
    Name     string `gorm:"type:varchar(50)"`
    Bio      string `gorm:"type:text"`
    Avatar   string `gorm:"type:varchar(255)"`
    Settings string `gorm:"type:json"`
}

常用类型标签

type Article struct {
    Title   string `gorm:"type:varchar(200)"`     // 指定长度
    Content string `gorm:"type:longtext"`          // 长文本
    Summary string `gorm:"type:text"`              // 文本
    Tags    string `gorm:"type:json"`              // JSON
    Image   []byte `gorm:"type:blob"`              // 二进制
}

字段大小限制

字符串长度

type User struct {
    Name     string `gorm:"size:50"`        // varchar(50)
    Email    string `gorm:"size:100"`       // varchar(100)
}

数字精度

浮点数指定精度:

type Product struct {
    Price float64 `gorm:"type:decimal(10,2)"`  // 10位总长,2位小数
}

NULL 处理

指针类型

type User struct {
    Name  string   // NOT NULL
    Email *string  // NULL
    Phone *string  // NULL
}

使用时:

email := "test@example.com"
user := User{
    Name:  "张三",
    Email: &email,  // 有值
    Phone: nil,     // NULL
}

sql.Null 类型

import "database/sql"

type User struct {
    Name  string
    Age   sql.NullInt64   // 可为 NULL 的整数
    Bio   sql.NullString  // 可为 NULL 的字符串
    Active sql.NullBool   // 可为 NULL 的布尔值
}

使用时:

user := User{
    Name: "张三",
    Age: sql.NullInt64{Int64: 25, Valid: true},
    Bio: sql.NullString{String: "", Valid: false},  // NULL
}

指针类型更简洁,sql.NullXxx 可以区分 NULL 和零值。

默认值

type User struct {
    Name   string `gorm:"default:'匿名'"`
    Age    int    `gorm:"default:18"`
    Active bool   `gorm:"default:true"`
    Role   string `gorm:"default:'user'"`
}

注意字符串默认值要加引号。

创建记录时,如果字段为零值,会使用默认值:

user := User{Name: "张三"}  // Age=0 会用默认值 18
db.Create(&user)

如果想用零值而不是默认值:

user := User{Name: "张三", Age: 0}
db.Omit("Age").Create(&user)  // 忽略 Age 字段

非空约束

type User struct {
    Name  string `gorm:"not null"`
    Email string `gorm:"not null"`
}

插入 NULL 值会报错。

字段排序

GORM 默认按字段定义顺序创建表列。如果需要指定:

type User struct {
    Name string `gorm:"column:name;type:varchar(100)"`
    Age  int    `gorm:"column:age;type:int"`
}

序列化字段

存储复杂结构:

type User struct {
    ID       uint
    Name     string
    Settings map[string]string `gorm:"type:json"`
    Tags     []string          `gorm:"type:json;serializer:json"`
}

serializer:json 让 GORM 自动序列化和反序列化。

计算字段

数据库生成的字段:

type Product struct {
    ID    uint
    Name  string
    Price float64
    Qty   int
    Total float64 `gorm:"->;type:GENERATED ALWAYS AS (price * qty) STORED"`
}

-> 表示只读字段。

枚举类型

type User struct {
    Status string `gorm:"type:enum('active','inactive','banned');default:'active'"`
    Role   string `gorm:"type:enum('admin','user','guest');default:'user'"`
}

或者用 Go 的 iota:

type Status int

const (
    StatusActive Status = iota
    StatusInactive
    StatusBanned
)

type User struct {
    Status Status `gorm:"type:tinyint;default:0"`
}

二进制数据

type File struct {
    ID      uint
    Name    string
    Content []byte `gorm:"type:blob"`
    Data    []byte `gorm:"type:longblob"`
}

小结

字段定义的关键点:

需求方法
自定义类型gorm:"type:varchar(50)"
字段长度gorm:"size:50"
允许 NULL使用指针类型或 sql.NullXxx
默认值gorm:"default:'value'"
非空约束gorm:"not null"
忽略字段gorm:"-"
只读字段gorm:"->"
序列化gorm:"serializer:json"

合理使用字段定义,可以让模型精确映射数据库结构。下一章介绍字段标签的完整用法。