メインコンテンツへスキップする

データベースマイグレーション

entのマイグレーションサポートでは、データベースのスキーマを、プロジェクトのルート下にあるent/migrate/schema.goで定義されたスキーマ・オブジェクトと一致させておくためのオプションが用意されています。

自動マイグレーション#

アプリケーションの初期時に自動マイグレーションを実行します。

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

Create は、 ent プロジェクトに必要なすべてのデータベースリソースを作成します。 デフォルトでは、Create"append-only"モードで動作します。つまり、新しいテーブルやインデックスの作成、テーブルへのカラムの追加、カラムの型の拡張のみを行います。 たとえば、intbigint に変更できます。

カラムやインデックスの削除はどのように行うのでしょうか?

リソースの削除#

WithDropIndexWithDropColumn はテーブルのカラムとインデックスを削除するための2つのオプションです。

package main
import (
"context"
"log"
"<project>/ent"
"<project>/ent/migrate"
)
func main() {
client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
if err != nil {
log.Fatalf("failed connecting to mysql: %v", err)
}
defer client.Close()
ctx := context.Background()
// マイグレーションの実行
err = client.Schema.Create(
ctx,
migrate.WithDropIndex(true),
migrate.WithDropColumn(true),
)
if err != nil {
log.Fatalf("failed creating schema resources: %v", err)
}
}

デバッグモードでマイグレーションを実行(すべての SQL クエリを出力) するには、以下を実行します。

err := client.Debug().Schema.Create(
ctx,
migrate.WithDropIndex(true),
migrate.WithDropColumn(true),
)
if err != nil {
log.Fatalf("failed creating schema resources: %v", err)
}

ユニバーサルID#

デフォルトでは、SQLの主キーはテーブルごとに1から始まります。これは、異なるタイプの複数のエンティティが同じIDを共有できることを意味します。 これは、ノードIDがUUIDになるAWS Neptuneとは異なっています。

GraphQLでは、オブジェクトIDが一意であることが要求されるため、この方法はうまく機能しません。

プロジェクトの Universal-ID サポートを有効にするには、マイグレーション時に WithGlobalUniqueID オプションを渡します。

package main
import (
"context"
"log"
"<project>/ent"
"<project>/ent/migrate"
)
func main() {
client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
if err != nil {
log.Fatalf("failed connecting to mysql: %v", err)
}
defer client.Close()
ctx := context.Background()
// マイグレーションの実行
if err := client.Schema.Create(ctx, migrate.WithGlobalUniqueID(true)); err != nil {
log.Fatalf("failed creating schema resources: %v", err)
}
}

どのような仕組みか? entのマイグレーションでは、 1<<32 の範囲をそれぞれのエンティティ (テーブル)のIDに割り当て, その情報を ent_typesというテーブルに格納します。 たとえば、タイプAはIDに[1,4294967296)の範囲の数値を用い、 タイプ B[4294967296,8589934592)の範囲の数値を用いるなどです。

このオプションが有効になっている場合、利用可能なテーブルの最大数は 65535 です。

オフラインモード#

オフラインモードでは、データベース上で実行する前に io.Writer にスキーマの変更を書き込むことができます。 データベース上で実行される前に SQL コマンドを検証する場合や、手動で実行する SQL スクリプト を取得する場合に役立ちます。

変更を出力する

package main
import (
"context"
"log"
"os"
"<project>/ent"
"<project>/ent/migrate"
)
func main() {
client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
if err != nil {
log.Fatalf("failed connecting to mysql: %v", err)
}
defer client.Close()
ctx := context.Background()
// マイグレーションによる変更を標準出力にダンプ
if err := client.Schema.WriteTo(ctx, os.Stdout); err != nil {
log.Fatalf("failed printing schema changes: %v", err)
}
}

変更をファイルに書き込む

package main
import (
"context"
"log"
"os"
"<project>/ent"
"<project>/ent/migrate"
)
func main() {
client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
if err != nil {
log.Fatalf("failed connecting to mysql: %v", err)
}
defer client.Close()
ctx := context.Background()
// マイグレーションによる変更をSQLスクリプトとしてダンプ
f, err := os.Create("migrate.sql")
if err != nil {
log.Fatalf("create migrate file: %v", err)
}
defer f.Close()
if err := client.Schema.WriteTo(ctx, f); err != nil {
log.Fatalf("failed printing schema changes: %v", err)
}
}

外部キー#

デフォルトでは、 ent はリレーションシップ(エッジ) を定義する際に外部キーを使用して、 データベース側で正確性と一貫性を強化します。

しかし、 ent は、 WithForeignKeys オプションを使用してこの機能を無効にするオプションも提供します。 このオプションをfalseに設定すると、スキーマのDDLに外部キーを作成しないようにマイグレーションします。エッジの検証とクリアは開発者が手動で行う必要があることに注意してください。

近い将来、アプリケーションレベルで外部キー制約を実装するためのフックのセットが提供できることを期待しています。

package main
import (
"context"
"log"
"<project>/ent"
"<project>/ent/migrate"
)
func main() {
client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
if err != nil {
log.Fatalf("failed connecting to mysql: %v", err)
}
defer client.Close()
ctx := context.Background()
// マイグレーションの実行
err = client.Schema.Create(
ctx,
migrate.WithForeignKeys(false), // Disable foreign keys.
)
if err != nil {
log.Fatalf("failed creating schema resources: %v", err)
}
}

マイグレーションフック#

Entフレームワークは、マイグレーションフェーズにフック(ミドルウェア) を追加するオプションを提供します。 このオプションは、マイグレーションの対象になるテーブルを修正またはフィルタリングしたり、データベースにカスタムリソースを作成したりする場合に最適です。

package main
import (
"context"
"log"
"<project>/ent"
"<project>/ent/migrate"
"entgo.io/ent/dialect/sql/schema"
)
func main() {
client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
if err != nil {
log.Fatalf("failed connecting to mysql: %v", err)
}
defer client.Close()
ctx := context.Background()
// マイグレーションの実行
err = client.Schema.Create(
ctx,
schema.WithHooks(func(next schema.Creator) schema.Creator {
return schema.CreateFunc(func(ctx context.Context, tables ...*schema.Table) error {
// ここでカスタムコードを実行
return next.Create(ctx, tables...)
})
}),
)
if err != nil {
log.Fatalf("failed creating schema resources: %v", err)
}
}