创建表

除了 AutoMigrate,GORM 还提供了手动创建表的方法。更精细的控制,适合复杂场景。

CreateTable

手动创建表:

db.CreateTable(&User{})

表不存在时创建,存在时报错。

检查表是否存在

if !db.Migrator().HasTable(&User{}) {
    db.CreateTable(&User{})
}

或者:

if !db.Migrator().HasTable("users") {
    db.CreateTable(&User{})
}

创建表选项

指定表选项:

db.Set("gorm:table_options", "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4").CreateTable(&User{})

MySQL 常用选项:

db.Set("gorm:table_options", `
    ENGINE=InnoDB
    DEFAULT CHARSET=utf8mb4
    COLLATE=utf8mb4_unicode_ci
    AUTO_INCREMENT=1000
`).CreateTable(&User{})

PostgreSQL:

db.Set("gorm:table_options", "WITH (OIDS=FALSE)").CreateTable(&User{})

完整模型定义

创建表前,完整定义模型:

type User struct {
    ID        uint           `gorm:"primaryKey;autoIncrement;comment:用户ID"`
    Name      string         `gorm:"type:varchar(50);not null;comment:用户名"`
    Email     string         `gorm:"type:varchar(100);uniqueIndex;comment:邮箱"`
    Password  string         `gorm:"type:varchar(255);not null;comment:密码"`
    Age       int            `gorm:"default:18;comment:年龄"`
    Status    string         `gorm:"type:enum('active','inactive');default:'active';comment:状态"`
    Bio       string         `gorm:"type:text;comment:简介"`
    CreatedAt time.Time      `gorm:"comment:创建时间"`
    UpdatedAt time.Time      `gorm:"comment:更新时间"`
    DeletedAt gorm.DeletedAt `gorm:"index;comment:删除时间"`
}

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

生成的 SQL:

CREATE TABLE `users` (
    `id` INT AUTO_INCREMENT COMMENT '用户ID',
    `name` VARCHAR(50) NOT NULL COMMENT '用户名',
    `email` VARCHAR(100) COMMENT '邮箱',
    `password` VARCHAR(255) NOT NULL COMMENT '密码',
    `age` INT DEFAULT 18 COMMENT '年龄',
    `status` ENUM('active','inactive') DEFAULT 'active' COMMENT '状态',
    `bio` TEXT COMMENT '简介',
    `created_at` DATETIME COMMENT '创建时间',
    `updated_at` DATETIME COMMENT '更新时间',
    `deleted_at` DATETIME COMMENT '删除时间',
    PRIMARY KEY (`id`),
    UNIQUE INDEX `idx_users_email` (`email`),
    INDEX `idx_users_deleted_at` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

多表创建

创建多个表:

db.CreateTable(&User{}, &Order{}, &Product{})

或者分别创建:

db.CreateTable(&User{})
db.CreateTable(&Order{})
db.CreateTable(&Product{})

带外键的表

创建带外键约束的表:

type Order struct {
    ID        uint
    UserID    uint
    User      User `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
    Amount    float64
}

db.CreateTable(&User{})
db.CreateTable(&Order{})

外键约束在创建 Order 表时建立。

带索引的表

模型中定义索引:

type User struct {
    ID    uint
    Name  string `gorm:"index:idx_name"`
    Email string `gorm:"uniqueIndex"`
    Age   int    `gorm:"index:idx_name_age,priority:2"`
    City  string `gorm:"index:idx_name_age,priority:1"`
}

复合索引 idx_name_age 包含 cityage,优先级决定顺序。

临时表

创建临时表:

db.Table("temp_users").CreateTable(&User{})

但这不会创建真正的临时表。要创建临时表需要原生 SQL:

db.Exec(`
    CREATE TEMPORARY TABLE temp_users (
        id INT PRIMARY KEY,
        name VARCHAR(50)
    )
`)

表名策略

自定义表名:

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

动态表名:

func (u *User) TableName() string {
    return "users_" + u.TenantID
}

全局表名策略:

db.NamingStrategy = schema.NamingStrategy{
    TablePrefix:   "t_",
    SingularTable: true,
}

删除表

db.DropTable(&User{})
db.DropTable("users")
db.DropTableIfExists(&User{})

批量删除

db.Migrator().DropTable(&User{}, &Order{}, &Product{})

实际案例

初始化数据库

func InitDatabase(db *gorm.DB) error {
    models := []interface{}{
        &User{},
        &Role{},
        &Permission{},
        &Order{},
        &Product{},
    }

    for _, model := range models {
        if !db.Migrator().HasTable(model) {
            if err := db.CreateTable(model).Error; err != nil {
                return err
            }
        }
    }

    return nil
}

带检查的创建

func EnsureTable(db *gorm.DB, model interface{}) error {
    if db.Migrator().HasTable(model) {
        return nil
    }
    return db.CreateTable(model).Error
}

小结

手动创建表提供更精细的控制。配合完整的模型定义,可以创建复杂的表结构。