id: migrate

title: Database Migration

ent 提供了迁移选项,迁移工具可以保持你项目根目录下的 ent/migrate/schema.go 内定义的 对象模式 与 数据库模式 保持一致。

自动迁移

在应用初始化时运行自动迁移的用法:

  1. if err := client.Schema.Create(ctx); err != nil {
  2. log.Fatalf("failed creating schema resources: %v", err)
  3. }

Create 创建 ent 项目需要的所有的数据库资源。默认情况下,Create 工作在 “append-only” 模式下;这意味着,它仅创建新的表和索引、将列追加到表或扩展列类型。例如,更改 intbigint.

怎么删除列或索引呢?

删除资源

WithDropIndexWithDropColumn 是删除表的列和索引的两个选项。

  1. package main
  2. import (
  3. "context"
  4. "log"
  5. "<project>/ent"
  6. "<project>/ent/migrate"
  7. )
  8. func main() {
  9. client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
  10. if err != nil {
  11. log.Fatalf("failed connecting to mysql: %v", err)
  12. }
  13. defer client.Close()
  14. ctx := context.Background()
  15. // 运行自动迁移.
  16. err = client.Schema.Create(
  17. ctx,
  18. migrate.WithDropIndex(true),
  19. migrate.WithDropColumn(true),
  20. )
  21. if err != nil {
  22. log.Fatalf("failed creating schema resources: %v", err)
  23. }
  24. }

如果想以调试模式运行迁移(打印出所有 SQL 语句),请运行:

  1. err := client.Debug().Schema.Create(
  2. ctx,
  3. migrate.WithDropIndex(true),
  4. migrate.WithDropColumn(true),
  5. )
  6. if err != nil {
  7. log.Fatalf("failed creating schema resources: %v", err)
  8. }

通用标识符

默认情况下,每个表的 SQL 主键从 1 开始;这意味着多个不同的实体可以拥有相同的 ID。这不同于 AWS Neptune,它使用的是 UUID。

如果你使用了 GraphQLent 将不能很好的工作,GraphQL 要求对象的 ID 是唯一的。

要为你的项目启用 通用ID 支持,需要将 WithGlobalUniqueID 选项传递给迁移工具。

  1. package main
  2. import (
  3. "context"
  4. "log"
  5. "<project>/ent"
  6. "<project>/ent/migrate"
  7. )
  8. func main() {
  9. client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
  10. if err != nil {
  11. log.Fatalf("failed connecting to mysql: %v", err)
  12. }
  13. defer client.Close()
  14. ctx := context.Background()
  15. // Run migration.
  16. if err := client.Schema.Create(ctx, migrate.WithGlobalUniqueID(true)); err != nil {
  17. log.Fatalf("failed creating schema resources: %v", err)
  18. }
  19. }

它是如何实现的? ent 迁移会为每个实体(表)的 ID 分配 1<<32 的范围,并将此信息存储在名为 ent_types 的表中。 例如,type A 的 ID 范围 [1,4294967296) 为,type B 的 ID 范围将为[4294967296,8589934592),以此类推。

需要注意的是,如果启用该选项,表的最大可能数量为 65535.

离线模式

离线模式允许你在模式修改之前将修改写入至一个 io.Writer. 这对于想在 SQL 语句运行之前对其进行验证,或想获取 SQL 脚本以手动运行是很有用。

Print changes

  1. package main
  2. import (
  3. "context"
  4. "log"
  5. "os"
  6. "<project>/ent"
  7. "<project>/ent/migrate"
  8. )
  9. func main() {
  10. client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
  11. if err != nil {
  12. log.Fatalf("failed connecting to mysql: %v", err)
  13. }
  14. defer client.Close()
  15. ctx := context.Background()
  16. // 将迁移更改转储至标准输出
  17. if err := client.Schema.WriteTo(ctx, os.Stdout); err != nil {
  18. log.Fatalf("failed printing schema changes: %v", err)
  19. }
  20. }

将更改写到文件

  1. package main
  2. import (
  3. "context"
  4. "log"
  5. "os"
  6. "<project>/ent"
  7. "<project>/ent/migrate"
  8. )
  9. func main() {
  10. client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
  11. if err != nil {
  12. log.Fatalf("failed connecting to mysql: %v", err)
  13. }
  14. defer client.Close()
  15. ctx := context.Background()
  16. // 将迁移更改转储至 SQL 脚本文件。
  17. f, err := os.Create("migrate.sql")
  18. if err != nil {
  19. log.Fatalf("create migrate file: %v", err)
  20. }
  21. defer f.Close()
  22. if err := client.Schema.WriteTo(ctx, f); err != nil {
  23. log.Fatalf("failed printing schema changes: %v", err)
  24. }
  25. }