表名设置

GORM 默认把结构体名转为蛇形复数作为表名。但实际项目中,表名规则各不相同,GORM 提供了多种自定义方式。

默认规则

type User struct {}      // → users
type OrderItem struct {} // → order_items
type Person struct {}    // → people

规则:驼峰转蛇形,再加复数。

TableName 方法

实现 TableName 方法自定义表名:

type User struct {
    ID   uint
    Name string
}

func (User) TableName() string {
    return "app_users"
}

这是最常用的方式,优先级最高。

动态表名

根据条件返回不同表名:

type Order struct {
    ID     uint
    UserID uint
    Amount float64
}

func (o Order) TableName() string {
    // 按用户分表
    if o.UserID > 0 {
        return fmt.Sprintf("orders_%d", o.UserID%10)
    }
    return "orders"
}

临时指定表名

查询时临时指定表名:

// 使用 Table 方法
db.Table("admin_users").Find(&users)

// 使用 Scopes
func WithTable(name string) func(db *gorm.DB) *gorm.DB {
    return func(db *gorm.DB) *gorm.DB {
        return db.Table(name)
    }
}

db.Scopes(WithTable("temp_users")).Find(&users)

全局表名策略

配置全局命名策略:

import "gorm.io/gorm/schema"

db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
    NamingStrategy: schema.NamingStrategy{
        TablePrefix:   "t_",    // 表名前缀
        SingularTable: true,    // 禁用复数
        NoLowerCase:   false,   // 是否保持原样
    },
})

TablePrefix

添加表名前缀:

NamingStrategy: schema.NamingStrategy{
    TablePrefix: "t_",
}
// User → t_users
// OrderItem → t_order_items

SingularTable

禁用复数:

NamingStrategy: schema.NamingStrategy{
    SingularTable: true,
}
// User → user
// OrderItem → order_item

自定义命名策略

完全自定义:

type CustomNamingStrategy struct {
    schema.NamingStrategy
}

func (ns CustomNamingStrategy) TableName(name string) string {
    // 全部转大写,加前缀
    return "TBL_" + strings.ToUpper(ns.NamingStrategy.TableName(name))
}

db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
    NamingStrategy: CustomNamingStrategy{},
})
// User → TBL_USERS

列名策略

列名也受命名策略影响:

NamingStrategy: schema.NamingStrategy{
    NoLowerCase: true,  // 保持原样
}
// UserName → UserName(而不是 user_name)

分表场景

按时间分表:

type Log struct {
    ID        uint
    Content   string
    CreatedAt time.Time
}

func (l Log) TableName() string {
    // 按月分表
    return "logs_" + l.CreatedAt.Format("200601")
}

// 或者查询时指定
func GetLogsByMonth(db *gorm.DB, year, month int) []Log {
    var logs []Log
    tableName := fmt.Sprintf("logs_%d%02d", year, month)
    db.Table(tableName).Find(&logs)
    return logs
}

按租户分表:

var currentTenant string

func SetTenant(tenant string) {
    currentTenant = tenant
}

func (User) TableName() string {
    return currentTenant + "_users"
}

指定 schema

PostgreSQL 的 schema:

func (User) TableName() string {
    return "public.users"  // public schema
}

func (Order) TableName() string {
    return "orders.orders"  // orders schema
}

小结

表名配置方式:

方式适用场景
默认规则简单项目,遵循约定
TableName 方法固定表名,优先级最高
Table 方法临时指定,灵活
全局策略统一前缀、禁用复数
动态 TableName分表场景

建议:

  • 项目初期确定表名规范
  • 用全局策略统一处理前缀
  • 特殊表用 TableName 方法覆盖
  • 分表场景用动态 TableName 或 Table 方法