5.7 KiB
5.7 KiB
tags, create time
| tags | create time | ||||||||
|---|---|---|---|---|---|---|---|---|---|
|
2026-04-28 00:00 |
模型定义
概述
模型(Model)是 GORM 操作的核心入口——一个普通的 Go struct 被 GORM「看见」后,就可以直接进行数据库操作。本章讲解如何通过 struct tag、命名约定和接口来自定义 GORM 对模型的解读。
什么是 Model?
[!definition] Model Model 是一个包含以下任一条件的 struct:
- 有主键字段
- 定义了
TableName()方法- 被
AutoMigrate、Create、Where等方法引用
type User struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"size:64;not null"`
}
// 这就是一个最简单的 GORM Model
表名规则
默认命名策略
GORM 使用 Table 方法来推导表名:
| 代码行为 | 结果 |
|---|---|
| 默认 | struct 名的蛇形复数形式(User → users) |
实现 TableName() string |
返回的字符串 |
使用 db.Table("xxx") |
查询时使用的表名(不会修改 Model 的 TableName) |
func (User) TableName() string {
return "sys_user" // 显式指定表名
}
[!tip] 多环境表名 不同环境下表名前缀不同?可以用环境变量 +
TableName()实现动态切换:func (User) TableName() string { if os.Getenv("ENV") == "test" { return "test_sys_user" } return "sys_user" }
字段 Tag 详解
完整 Tag 语法
gorm:"column:name;type:bigint;not null;default:0;uniqueIndex;index;comment:用户ID"
| Tag 关键字 | 作用 | 示例 |
|---|---|---|
column |
映射列名 | column:user_id |
type |
列类型覆盖 | type:varchar(128) |
not null |
NOT NULL 约束 | not null |
default |
默认值 | default:'unknown' |
primaryKey |
主键 | primaryKey |
autoIncrement |
自增 | autoIncrement |
uniqueIndex |
唯一索引 | uniqueIndex:idx_name |
index |
普通索引 | index:idx_status |
comment |
注释(MySQL) | comment:用户名 |
<- |
字段写入控制 | <-:true / <-:false / <-:create / <-:update |
-> |
只读/只写 | ->:true(只读) / <-:false(不写入) |
- |
忽略此字段 | - |
写入权限控制
type Product struct {
ID uint `gorm:"primaryKey;autoIncrement"`
Name string `gorm:"not null;<-:create"` // 仅创建时可写入
Price float64 `gorm:"not null;<-:true;->:true"` // 读写均可(默认)
CreatedAt time.Time `gorm:"<-:create;->:true;autoTime"` // 仅创建时自动填充
UpdatedAt time.Time `gorm:"<-:update;->:true;autoTime"` // 仅更新时自动填充
ViewCount int `gorm:"->:false;<-:false"` // 完全忽略(非 DB 字段)
}
[!example] 方向记忆法
<-表示数据流向数据库(写入),->表示数据从数据库流出(读取)。箭头方向就是数据的方向。
字段类型映射
| Go 类型 | 推荐 DB 类型 | 说明 |
|---|---|---|
int, int64 |
BIGINT | GORM 默认以 int64 处理 |
uint, uint64 |
BIGINT UNSIGNED | — |
string |
VARCHAR(n) | 需手动指定 size |
bool |
TINYINT(1) / BOOLEAN | — |
float64 |
DOUBLE | — |
time.Time |
DATETIME / TIMESTAMP | 配合 autoTime tag |
[]byte |
BLOB / BYTEA | 二进制数据 |
json.RawMessage |
JSON | JSON 序列化字段 |
autoTime 自动时间戳
type Article struct {
ID uint `gorm:"primaryKey"`
Title string `gorm:"size:128;not null"`
CreatedAt time.Time `gorm:"autoTime;createTime"` // 创建时自动填充
UpdatedAt time.Time `gorm:"autoTime;updateTime"` // 更新时自动填充
}
[!note] createTime / updateTime 这两个子 tag 是 GORM v2 的增强功能,配合
autoTime使用。单独autoTime只更新时间,加上createTime后才会在插入时设置 CreatedAt。
主键策略
默认策略:ID uint
type User struct {
ID uint // GORM 默认将名为 ID 的字段视为主键
Name string
}
UUID 主键
import "github.com/google/uuid"
type Order struct {
ID uuid.UUID `gorm:"type:char(36);primaryKey"`
Code string `gorm:"uniqueIndex;not null"`
}
// 在 Create 前生成 UUID
order.ID = uuid.New()
db.Create(&order)
复合主键
type OrderItem struct {
OrderID uint `gorm:"primaryKey"`
ProductID uint `gorm:"primaryKey"`
Quantity int `gorm:"not null"`
}
// 生成表结构:PRIMARY KEY (order_id, product_id)
[!tip] 复合主键注意事项 使用复合主键时,
First()和Take()将无法工作(因为它们期望单主键),必须使用Where()精确定位。
自定义类型作为字段
当内置类型不够用时,可以实现 GORM 接口:
type MyType int
func (m MyType) GORMDataType() string {
return "INT"
}
func (m MyType) Value() (driver.Value, error) {
return int(m), nil // ScannerValuer 接口的 Value 方法
}
模型设计流程图
flowchart TD
A[定义 struct] --> B{有无 ID 字段?}
B -->|有| C["ID 作主键<br/>uint/int64"]
B -->|无| D{自定义 TableName?}
D -->|实现了| E[按 TableName 返回值]
D -->|未实现| F["struct 名蛇形复数"]
C --> G[添加字段 tag]
E --> G
G --> H{需要特殊类型?}
H -->|是| I[实现 GORMDataType / Valuer]
H -->|否| J[完成]
I --> J
style A fill:#4FC08D,color:#fff
style C fill:#3B82F6,color:#fff
style I fill:#EAB308,color:#fff
style J fill:#A0AEC0,color:#fff