模型定义详解
第二章:模型定义详解
2.1 基础模型结构
内置 gorm.Model
type Model struct {
ID uint `gorm:"primaryKey"` // 自增主键
CreatedAt time.Time // 创建时间
UpdatedAt time.Time // 更新时间
DeletedAt gorm.DeletedAt `gorm:"index"` // 软删除时间戳
}
使用方式:
type User struct {
gorm.Model
Name string
}
自定义基础模型
type BaseModel struct {
ID uint64 `gorm:"primaryKey;autoIncrement;comment:主键ID"`
CreatedAt time.Time `gorm:"index;comment:创建时间"`
UpdatedAt time.Time `gorm:"comment:更新时间"`
DeletedAt gorm.DeletedAt `gorm:"index;comment:删除时间"`
}
type User struct {
BaseModel
Name string `gorm:"comment:用户名"`
}
2.2 字段标签(Tags)
GORM 通过结构体标签配置字段属性:
常用标签
| 标签 | 说明 | 示例 |
|---|---|---|
column |
指定列名 | gorm:"column:user_name" |
type |
指定数据类型 | gorm:"type:varchar(100)" |
size |
字段大小 | gorm:"size:255" |
primaryKey |
设为主键 | gorm:"primaryKey" |
unique |
唯一约束 | gorm:"unique" |
uniqueIndex |
唯一索引 | gorm:"uniqueIndex:idx_email" |
index |
普通索引 | gorm:"index:idx_name" |
default |
默认值 | gorm:"default:'unknown'" |
not null |
非空约束 | gorm:"not null" |
autoIncrement |
自增 | gorm:"autoIncrement" |
comment |
字段注释 | gorm:"comment:用户姓名" |
embedded |
嵌入字段 | gorm:"embedded" |
embeddedPrefix |
嵌入前缀 | gorm:"embeddedPrefix:info_" |
- |
忽略字段 | gorm:"-" |
完整示例
type Product struct {
ID uint `gorm:"primaryKey;autoIncrement;column:product_id"`
Code string `gorm:"uniqueIndex;size:100;not null;comment:产品编码"`
Name string `gorm:"type:varchar(200);index:idx_name;comment:产品名称"`
Price float64 `gorm:"type:decimal(10,2);default:0;comment:价格"`
Description string `gorm:"type:text;comment:产品描述"`
Status int `gorm:"default:1;comment:状态:1-上架 2-下架"`
IsDeleted bool `gorm:"default:false;-"` // 忽略该字段
CreatedAt time.Time
UpdatedAt time.Time
}
2.3 主键配置
单字段主键
type User struct {
ID uint `gorm:"primaryKey"`
Name string
}
复合主键
type ProductCategory struct {
ProductID uint `gorm:"primaryKey"`
CategoryID uint `gorm:"primaryKey"`
SortOrder int
}
注意:GORM 默认使用
ID作为主键,启用复合主键后会禁用默认主键行为。
自增控制
type User struct {
ID uint64 `gorm:"primaryKey;autoIncrement:false"` // 禁用自增
Name string
}
2.4 索引配置
单列索引
type User struct {
Name string `gorm:"index"` // 自动命名索引
Email string `gorm:"index:idx_email"` // 指定索引名
Phone string `gorm:"uniqueIndex"` // 唯一索引
}
复合索引
type User struct {
FirstName string `gorm:"index:idx_name"`
LastName string `gorm:"index:idx_name"`
// 等效于:CREATE INDEX idx_name ON users(first_name, last_name)
}
索引选项
type User struct {
Name string `gorm:"index:idx_name,unique,sort:desc"` // 唯一+降序
Age int `gorm:"index:idx_age,class:FULLTEXT,option:WITH PARSER ngram"`
// class: FULLTEXT, SPATIAL
}
表级索引(GORM 2.0+)
type User struct {
Name string
Age int
}
func (User) Indexes() []schema.Index {
return []schema.Index{
{
Name: "idx_name_age",
Fields: []schema.IndexOption{
{Field: "Name", Sort: "asc"},
{Field: "Age", Sort: "desc"},
},
},
}
}
2.5 嵌入结构体
普通嵌入
type Author struct {
Name string
Email string
}
type Blog struct {
ID int
Author Author // 嵌入结构体
Content string
}
// 表结构: id, name, email, content
带前缀嵌入
type Blog struct {
ID int
Author Author `gorm:"embeddedPrefix:author_"`
Reviewer Author `gorm:"embeddedPrefix:reviewer_"`
Content string
}
// 表结构: id, author_name, author_email, reviewer_name, reviewer_email, content
2.6 字段权限控制
读写权限
type User struct {
Name string
// <-:create 只允许创建(读/写入),不允许更新
UUID string `gorm:"<-:create"`
// <-:update 只允许更新,不允许创建(如某些计数器)
Counter int `gorm:"<-:update"`
// <-:false 无写入权限,只读
JoinTime time.Time `gorm:"<-:false"`
// ->:false 无读取权限(敏感字段)
Password string `gorm:"->:false"`
// - 无读写权限(完全忽略)
Secret string `gorm:"-"`
}
时间戳追踪
type User struct {
CreatedAt time.Time // 自动设置为创建时间
UpdatedAt time.Time // 自动设置为更新时间
DeletedAt gorm.DeletedAt // 软删除标记
}
禁用时间戳追踪:
type User struct {
CreatedAt time.Time `gorm:"autoCreateTime:false"`
UpdatedAt time.Time `gorm:"autoUpdateTime:false"`
}
自定义时间戳字段名:
type User struct {
CreateTime int64 `gorm:"autoCreateTime"`
UpdateTime int64 `gorm:"autoUpdateTime:milli"` // 毫秒时间戳
}
2.7 表名配置
全局表名前缀
func main() {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
// 设置全局表名前缀
db.NamingStrategy = schema.NamingStrategy{
TablePrefix: "t_", // 表名前缀
SingularTable: true, // 使用单数表名
}
}
模型级别表名
type User struct {}
// TableName 指定表名
func (User) TableName() string {
return "sys_user"
}
动态表名
type Order struct {}
func (Order) TableName() string {
// 按月分表
return "order_" + time.Now().Format("200601")
}
使用 Scopes 实现动态表名查询:
func TableName(name string) func(*gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
return db.Table(name)
}
}
// 使用
db.Scopes(TableName("order_202401")).Find(&orders)
2.8 数据库特定类型
MySQL
type MySQLProduct struct {
ID uint `gorm:"primaryKey"`
JSON datatypes.JSON // JSON 类型(需 gorm.io/datatypes)
Status sql.NullString // 可空字符串
// 枚举类型
gen:mysql,"enum('active','inactive')"`
}
PostgreSQL
type PostgresProduct struct {
ID uint
Tags pq.StringArray `gorm:"type:text[]"` // 数组类型
Info datatypes.JSON // JSONB 类型
Point datatypes.Point // 地理坐标
}
SQLite
type SQLiteProduct struct {
ID uint
Data datatypes.JSON // SQLite 3.38+ 支持 JSON
}
2.9 完整模型示例
package models
import (
"time"
"gorm.io/gorm"
"gorm.io/datatypes"
)
// BaseModel 基础模型
type BaseModel struct {
ID uint64 `gorm:"primaryKey;autoIncrement;comment:主键ID"`
CreatedAt time.Time `gorm:"index;comment:创建时间"`
UpdatedAt time.Time `gorm:"comment:更新时间"`
DeletedAt gorm.DeletedAt `gorm:"index;comment:删除时间"`
}
// Profile 用户信息(嵌入用)
type Profile struct {
Avatar string `gorm:"size:500;comment:头像URL"`
Nickname string `gorm:"size:50;comment:昵称"`
Bio string `gorm:"size:500;comment:简介"`
Gender int8 `gorm:"default:0;comment:性别:0-未知 1-男 2-女"`
}
// User 用户模型
type User struct {
BaseModel
Username string `gorm:"size:50;uniqueIndex;not null;comment:用户名"`
Password string `gorm:"size:255;not null;->:false;comment:密码"` // 只写
Email string `gorm:"size:100;uniqueIndex;comment:邮箱"`
Phone *string `gorm:"size:20;uniqueIndex;comment:手机号"` // 指针表示可空
Status int8 `gorm:"default:1;index;comment:状态:1-正常 2-禁用"`
Profile `gorm:"embedded"`
Settings datatypes.JSON `gorm:"comment:用户设置JSON"`
LastLogin *time.Time `gorm:"comment:最后登录时间"`
}
func (User) TableName() string {
return "sys_user"
}
func (User) Indexes() []schema.Index {
return []schema.Index{
{
Name: "idx_status_created",
Fields: []schema.IndexOption{
{Field: "Status"},
{Field: "CreatedAt"},
},
},
}
}
// Category 分类
type Category struct {
BaseModel
Name string `gorm:"size:50;not null;comment:分类名称"`
ParentID *uint64 `gorm:"index;comment:父分类ID"`
Sort int `gorm:"default:0;comment:排序"`
}
// Article 文章
type Article struct {
BaseModel
Title string `gorm:"size:200;not null;index;comment:标题"`
Content string `gorm:"type:longtext;comment:内容"`
Summary string `gorm:"size:500;comment:摘要"`
Cover string `gorm:"size:500;comment:封面图"`
AuthorID uint64 `gorm:"index;not null;comment:作者ID"`
CategoryID uint64 `gorm:"index;comment:分类ID"`
Tags datatypes.JSON `gorm:"comment:标签JSON数组"`
ViewCount int `gorm:"default:0;comment:浏览量"`
Status int8 `gorm:"default:1;comment:状态:1-草稿 2-已发布 3-下架"`
PublishedAt *time.Time `gorm:"comment:发布时间"`
}
// Comment 评论(演示复合索引)
type Comment struct {
BaseModel
ArticleID uint64 `gorm:"primaryKey;autoIncrement:false;comment:文章ID"`
Floor int `gorm:"primaryKey;autoIncrement:false;comment:楼层"`
UserID uint64 `gorm:"index;comment:用户ID"`
Content string `gorm:"size:1000;comment:内容"`
}
2.10 练习题
- 定义一个
Order模型,包含订单号(唯一)、用户ID、总金额、状态、收货地址信息(嵌入) - 给
Order添加复合索引:用户ID + 创建时间 - 创建一个
OrderItem模型,使用复合主键(OrderID + ProductID)
2.11 小结
本章详细介绍了 GORM 模型定义的各种技巧,包括字段标签、索引、嵌入结构体等。合理的模型定义是高效使用 GORM 的基础。
本文代码地址:https://github.com/LittleMoreInteresting/gorm_study
欢迎关注公众号,一起学习进步!