模型定义详解


第二章:模型定义详解

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 练习题

  1. 定义一个 Order 模型,包含订单号(唯一)、用户ID、总金额、状态、收货地址信息(嵌入)
  2. Order 添加复合索引:用户ID + 创建时间
  3. 创建一个 OrderItem 模型,使用复合主键(OrderID + ProductID)

2.11 小结

本章详细介绍了 GORM 模型定义的各种技巧,包括字段标签、索引、嵌入结构体等。合理的模型定义是高效使用 GORM 的基础。


本文代码地址:https://github.com/LittleMoreInteresting/gorm_study

欢迎关注公众号,一起学习进步!

如有疑问关注公众号给我留言
wx

关注公众号

©2017-2023 鲁ICP备17023316号-1 Powered by Hugo