遷移

自動遷移

自動遷移您的架構,以保持架構最新。

注意:AutoMigrate 將建立資料表、遺失的外來鍵、約束、欄位和索引。如果大小、精度、可為 Null 的狀態變更,它將變更現有欄位的類型。它不會刪除未使用的欄位以保護您的資料。

db.AutoMigrate(&User{})

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

// Add table suffix when creating tables
db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&User{})

注意 AutoMigrate 會自動建立資料庫外來鍵約束,您可以在初始化期間停用此功能,例如

db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
DisableForeignKeyConstraintWhenMigrating: true,
})

遷移器介面

GORM 提供一個遷移器介面,其中包含每個資料庫的統一 API 介面,可供用來建置與資料庫無關的遷移,例如

SQLite 不支援 ALTER COLUMNDROP COLUMN,GORM 將建立一個與您嘗試變更的資料表相同的新資料表,複製所有資料,刪除舊資料表,重新命名新資料表

MySQL 不支援某些版本的重新命名欄位、索引,GORM 將根據您使用的 MySQL 版本執行不同的 SQL

type Migrator interface {
// AutoMigrate
AutoMigrate(dst ...interface{}) error

// Database
CurrentDatabase() string
FullDataTypeOf(*schema.Field) clause.Expr

// Tables
CreateTable(dst ...interface{}) error
DropTable(dst ...interface{}) error
HasTable(dst interface{}) bool
RenameTable(oldName, newName interface{}) error
GetTables() (tableList []string, err error)

// Columns
AddColumn(dst interface{}, field string) error
DropColumn(dst interface{}, field string) error
AlterColumn(dst interface{}, field string) error
MigrateColumn(dst interface{}, field *schema.Field, columnType ColumnType) error
HasColumn(dst interface{}, field string) bool
RenameColumn(dst interface{}, oldName, field string) error
ColumnTypes(dst interface{}) ([]ColumnType, error)

// Views
CreateView(name string, option ViewOption) error
DropView(name string) error

// Constraints
CreateConstraint(dst interface{}, name string) error
DropConstraint(dst interface{}, name string) error
HasConstraint(dst interface{}, name string) bool

// Indexes
CreateIndex(dst interface{}, name string) error
DropIndex(dst interface{}, name string) error
HasIndex(dst interface{}, name string) bool
RenameIndex(dst interface{}, oldName, newName string) error
}

目前資料庫

傳回目前使用的資料庫名稱

db.Migrator().CurrentDatabase()

資料表

// Create table for `User`
db.Migrator().CreateTable(&User{})

// Append "ENGINE=InnoDB" to the creating table SQL for `User`
db.Set("gorm:table_options", "ENGINE=InnoDB").Migrator().CreateTable(&User{})

// Check table for `User` exists or not
db.Migrator().HasTable(&User{})
db.Migrator().HasTable("users")

// Drop table if exists (will ignore or delete foreign key constraints when dropping)
db.Migrator().DropTable(&User{})
db.Migrator().DropTable("users")

// Rename old table to new table
db.Migrator().RenameTable(&User{}, &UserInfo{})
db.Migrator().RenameTable("users", "user_infos")

欄位

type User struct {
Name string
}

// Add name field
db.Migrator().AddColumn(&User{}, "Name")
// Drop name field
db.Migrator().DropColumn(&User{}, "Name")
// Alter name field
db.Migrator().AlterColumn(&User{}, "Name")
// Check column exists
db.Migrator().HasColumn(&User{}, "Name")

type User struct {
Name string
NewName string
}

// Rename column to new name
db.Migrator().RenameColumn(&User{}, "Name", "NewName")
db.Migrator().RenameColumn(&User{}, "name", "new_name")

// ColumnTypes
db.Migrator().ColumnTypes(&User{}) ([]gorm.ColumnType, error)

type ColumnType interface {
Name() string
DatabaseTypeName() string // varchar
ColumnType() (columnType string, ok bool) // varchar(64)
PrimaryKey() (isPrimaryKey bool, ok bool)
AutoIncrement() (isAutoIncrement bool, ok bool)
Length() (length int64, ok bool)
DecimalSize() (precision int64, scale int64, ok bool)
Nullable() (nullable bool, ok bool)
Unique() (unique bool, ok bool)
ScanType() reflect.Type
Comment() (value string, ok bool)
DefaultValue() (value string, ok bool)
}

檢視

透過 ViewOption 建立檢視。關於 ViewOption

  • Query 是必要的 子查詢
  • 如果 Replace 為 true,執行 CREATE OR REPLACE,否則執行 CREATE
  • 如果 CheckOption 不為空,附加到 sql,例如 WITH LOCAL CHECK OPTION

注意 SQLite 目前不支援 ViewOption 中的 Replace

query := db.Model(&User{}).Where("age > ?", 20)

// Create View
db.Migrator().CreateView("users_pets", gorm.ViewOption{Query: query})
// CREATE VIEW `users_view` AS SELECT * FROM `users` WHERE age > 20

// Create or Replace View
db.Migrator().CreateView("users_pets", gorm.ViewOption{Query: query, Replace: true})
// CREATE OR REPLACE VIEW `users_pets` AS SELECT * FROM `users` WHERE age > 20

// Create View With Check Option
db.Migrator().CreateView("users_pets", gorm.ViewOption{Query: query, CheckOption: "WITH CHECK OPTION"})
// CREATE VIEW `users_pets` AS SELECT * FROM `users` WHERE age > 20 WITH CHECK OPTION

// Drop View
db.Migrator().DropView("users_pets")
// DROP VIEW IF EXISTS "users_pets"

約束

type UserIndex struct {
Name string `gorm:"check:name_checker,name <> 'jinzhu'"`
}

// Create constraint
db.Migrator().CreateConstraint(&User{}, "name_checker")

// Drop constraint
db.Migrator().DropConstraint(&User{}, "name_checker")

// Check constraint exists
db.Migrator().HasConstraint(&User{}, "name_checker")

關係建立外來鍵

type User struct {
gorm.Model
CreditCards []CreditCard
}

type CreditCard struct {
gorm.Model
Number string
UserID uint
}

// create database foreign key for user & credit_cards
db.Migrator().CreateConstraint(&User{}, "CreditCards")
db.Migrator().CreateConstraint(&User{}, "fk_users_credit_cards")
// ALTER TABLE `credit_cards` ADD CONSTRAINT `fk_users_credit_cards` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`)

// check database foreign key for user & credit_cards exists or not
db.Migrator().HasConstraint(&User{}, "CreditCards")
db.Migrator().HasConstraint(&User{}, "fk_users_credit_cards")

// drop database foreign key for user & credit_cards
db.Migrator().DropConstraint(&User{}, "CreditCards")
db.Migrator().DropConstraint(&User{}, "fk_users_credit_cards")

索引

type User struct {
gorm.Model
Name string `gorm:"size:255;index:idx_name,unique"`
}

// Create index for Name field
db.Migrator().CreateIndex(&User{}, "Name")
db.Migrator().CreateIndex(&User{}, "idx_name")

// Drop index for Name field
db.Migrator().DropIndex(&User{}, "Name")
db.Migrator().DropIndex(&User{}, "idx_name")

// Check Index exists
db.Migrator().HasIndex(&User{}, "Name")
db.Migrator().HasIndex(&User{}, "idx_name")

type User struct {
gorm.Model
Name string `gorm:"size:255;index:idx_name,unique"`
Name2 string `gorm:"size:255;index:idx_name_2,unique"`
}
// Rename index name
db.Migrator().RenameIndex(&User{}, "Name", "Name2")
db.Migrator().RenameIndex(&User{}, "idx_name", "idx_name_2")

約束

GORM 在自動遷移或建立資料表時會建立約束,詳情請參閱 約束資料庫索引

Atlas 整合

Atlas 是一個開源資料庫遷移工具,與 GORM 有官方整合。

儘管 GORM 的 AutoMigrate 功能在大部分情況下都能運作,但在某些時候你可能需要切換到 版本化遷移策略。

一旦發生這種情況,規劃遷移腳本並確保它們與 GORM 在執行階段的預期相符的責任就轉移到開發人員身上。

Atlas 可以使用官方 GORM Provider 為開發人員自動規劃資料庫架構遷移。在配置提供者後,你可以透過執行以下指令自動規劃遷移

atlas migrate diff --env gorm

若要了解如何將 Atlas 與 GORM 搭配使用,請查看 官方文件

其他遷移工具

若要將 GORM 與其他基於 Go 的遷移工具搭配使用,GORM 提供了一個通用的資料庫介面,這對你來說可能很有幫助。

// returns `*sql.DB`
db.DB()

有關更多詳細資訊,請參閱 通用介面

白金贊助商

金牌贊助商

白金贊助商

金牌贊助商