多个模型有相同字段时,重复定义很烦。GORM 支持结构体嵌套,可以把公共字段提取出来复用。
type BaseModel struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
}
type User struct {
BaseModel
Name string
Email string
}
type Post struct {
BaseModel
Title string
Content string
}
User 和 Post 都会继承 BaseModel 的字段。
GORM 内置的 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 User struct {
BaseModel `gorm:"embedded"`
Name string
}
默认就是嵌入的,embedded 标签通常省略。
给嵌入字段加前缀:
type User struct {
BaseModel `gorm:"embedded;embeddedPrefix:base_"`
Name string
}
生成的表结构:
CREATE TABLE users (
base_id bigint unsigned,
base_created_at datetime,
base_updated_at datetime,
name longtext
);
type TimestampModel struct {
CreatedAt time.Time
UpdatedAt time.Time
}
type BaseModel struct {
TimestampModel
ID uint `gorm:"primaryKey"`
}
type User struct {
BaseModel
Name string
}
嵌入结构体中的关联字段:
type BaseEntity struct {
CreatedBy uint
Creator User `gorm:"foreignKey:CreatedBy"`
}
type Post struct {
BaseEntity
Title string
}
可以覆盖嵌入字段:
type BaseModel struct {
ID uint `gorm:"primaryKey"`
}
type User struct {
BaseModel
ID uint `gorm:"primaryKey;autoIncrement:false"` // 覆盖
Name string
}
嵌入指针类型:
type User struct {
*BaseModel
Name string
}
注意:指针嵌入时,如果嵌入结构为 nil,所有字段都是 NULL。
嵌入非指针:
type User struct {
BaseModel // 值类型嵌入
Name string
}
推荐值类型嵌入,避免 nil 问题。
type AuditModel struct {
CreatedAt time.Time
CreatedBy uint
UpdatedAt time.Time
UpdatedBy uint
}
type Order struct {
ID uint `gorm:"primaryKey"`
AuditModel
Amount float64
}
type SoftDeleteModel struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
type Product struct {
SoftDeleteModel
Name string
Price float64
}
type TenantModel struct {
ID uint `gorm:"primaryKey"`
TenantID uint `gorm:"index"`
CreatedAt time.Time
}
type Order struct {
TenantModel
Amount float64
}
嵌入结构体的方法会被继承:
func (m BaseModel) BeforeCreate(tx *gorm.DB) error {
// 会被 User 继承
}
type User struct {
BaseModel
Name string
}
嵌入后,类型关系:
user := User{}
_, ok := interface{}(user).(BaseModel) // false
_, ok := interface{}(&user).(*BaseModel) // false
嵌入不是继承,是组合。
嵌入字段在 JSON 中会展开:
user := User{
BaseModel: BaseModel{ID: 1},
Name: "张三",
}
// JSON: {"ID":1,"Name":"张三"}
如果想要嵌套结构:
type User struct {
Base *BaseModel `json:"base"`
Name string `json:"name"`
}
模型嵌套的要点:
gorm.Model 提供常用字段embeddedPrefix 添加字段前缀合理使用嵌套可以减少重复代码,让模型定义更清晰。