794 字
4 分钟
模型定义与标签
GORM 模型定义与标签
基础模型
type User struct { ID uint `gorm:"primaryKey"` Name string `gorm:"size:64;not null"` Email string `gorm:"size:255;uniqueIndex;not null"` Age int `gorm:"default:0"` Profile UserProfile // has one Orders []Order // has many CreatedAt time.Time UpdatedAt time.Time DeletedAt gorm.DeletedAt `gorm:"index"`}GORM 会根据字段名和类型推断列名、主键、时间字段和关联关系。显式标签适合表达数据库约束,不要把所有字段都堆满标签而失去可读性。
gorm.Model
type Product struct { gorm.Model // ID、CreatedAt、UpdatedAt、DeletedAt Code string `gorm:"uniqueIndex;not null"` Price int64 `gorm:"check:price >= 0"`}嵌入 gorm.Model 会带来软删除字段。软删除记录通常不会被普通查询返回;需要查看全部记录时使用 Unscoped()。
常用标签
| 标签 | 示例 | 作用 |
|---|---|---|
primaryKey | gorm:"primaryKey" | 主键 |
column | gorm:"column:user_name" | 指定列名 |
type | gorm:"type:decimal(18,2)" | 指定数据库类型 |
size | gorm:"size:128" | 字符串长度 |
not null | gorm:"not null" | 非空约束 |
default | gorm:"default:active" | 数据库默认值 |
uniqueIndex | gorm:"uniqueIndex:uk_email" | 唯一索引 |
index | gorm:"index:idx_status_created" | 普通索引 |
- | gorm:"-" | 不映射到数据库 |
embedded | gorm:"embedded" | 展开嵌入结构字段 |
serializer | gorm:"serializer:json" | 序列化字段 |
多个标签用分号分隔:
Email string `gorm:"size:255;not null;uniqueIndex:uk_users_email"`零值与默认值
type User struct { Name string `gorm:"default:guest"` Active bool `gorm:"default:true"`}使用 Create 时,GORM 对具有默认值的字段可能跳过 Go 零值,让数据库填充默认值。若业务需要明确写入 false、0 或空字符串,应使用指针、map 或明确的列更新策略,并在测试中确认目标数据库行为。
时间字段
字段名为 CreatedAt、UpdatedAt 时,GORM 会自动维护时间:
type Audit struct { CreatedAt time.Time UpdatedAt time.Time}也可以使用 Unix 时间戳字段,但必须根据字段类型和标签配置,不要同时把同一业务时间映射到多个字段而没有明确来源。
软删除
type User struct { ID uint DeletedAt gorm.DeletedAt `gorm:"index"`}
db.Delete(&user) // 设置 DeletedAt,不物理删除db.Unscoped().Find(&users) // 包含已删除记录db.Unscoped().Delete(&user) // 物理删除,谨慎使用软删除是查询范围行为,不等同于数据库级别的归档或合规删除;需要定期清理时应设计独立任务并确认恢复策略。
表名与列名
默认情况下,结构体名会映射为蛇形复数表名,字段名映射为蛇形列名。单个模型可通过 TableName() 覆盖表名:
func (User) TableName() string { return "app_user" }不要在 TableName() 中根据运行时参数返回不同结果;表名应是稳定的模型约定。
索引与约束
type LoginRecord struct { UserID uint `gorm:"index:idx_user_created,priority:1"` CreatedAt time.Time `gorm:"index:idx_user_created,priority:2"` IP string `gorm:"size:45"`}索引是否有效取决于查询条件、选择性、排序和数据分布。先根据实际查询建立索引,再用 EXPLAIN 验证,不要给每个字段都加索引。
模型设计建议
- 数据库模型、请求 DTO、响应 DTO 分开,避免直接把内部字段暴露给 API。
- 密码等敏感字段不应出现在日志和 JSON 响应中,可使用
json:"-"或单独的响应结构。 - 外键字段和关联字段命名保持一致,例如
UserID对应User。 - 业务状态使用明确的类型或常量,避免在查询中散落魔法字符串。
- 先确定删除策略,再决定是否使用软删除。
官方资料
分享文章
生成精美分享图或复制链接,与更多人分享本文。
继续阅读
换条路线
从其他文章中稳定抽取
最后更新于 ,距今已过 77 天
部分内容可能已过时