移行の管理

モデルが変更されると、通常の開発の一環として移行が追加および削除され、移行ファイルがプロジェクトのソース管理にチェックインされます。 移行を管理するには、最初に EF Core コマンドライン ツールをインストールする必要があります。

ヒント

DbContext がスタートアップ プロジェクトとは異なるアセンブリに含まれている場合、ターゲットとスタートアップ プロジェクトはパッケージ マネージャー コンソール ツールまたは .NET Core CLI ツールのいずれかに明示的に指定できます。

移行を追加する

モデルが変更された後、その変更の移行を追加できます。

dotnet ef migrations add AddBlogCreatedTimestamp

移行名は、バージョン管理システムのコミット メッセージのように使用できます。 たとえば、変更が Blog エンティティの新しい CreatedTimestamp プロパティである場合、AddBlogCreatedTimestamp などの名前を選ぶことができます。

[移行] ディレクトリの下で 3 つのファイルがプロジェクトに追加されます。

  • XXXXXXXXXXXXXX_AddCreatedTimestamp.cs-- メインの移行ファイル。 (Up で) 移行を適用し、(Down で) それを元に戻すために必要な操作が含まれます。
  • XXXXXXXXXXXXXX_AddCreatedTimestamp.Designer.cs-- 移行のメタデータ ファイル。 EF によって使用される情報が含まれます。
  • MyContextModelSnapshot.cs--現在のモデルのスナップショット。 次の移行を追加するときの変更内容の決定に使用されます。

変更の進行がわかるように、ファイル名のタイムスタンプは時系列順で維持されます。

名前空間

移行ファイルは自由に移動し、手動で名前空間を変更できます。 新しい移行は前回の移行の兄弟として作成されます。 または、生成時に次のようにディレクトリを指定することもできます。

dotnet ef migrations add InitialCreate --output-dir Your/Directory

Note

--namespace を使用して、ディレクトリとは別に名前空間を変更することもできます。

移行コードをカスタマイズする

EF Core では通常正確な移行が生成されますが、常にコードを確認し、必要な変更に対応していることを確認してください。場合によっては、これを行う必要があります。

列名の変更

移行をカスタマイズする必要がある一例として、プロパティの名前を変更する場合があります。 たとえば、プロパティの名前を Name から FullName に変更すると、EF Core によって次の移行が生成されます。

migrationBuilder.DropColumn(
    name: "Name",
    table: "Customers");

migrationBuilder.AddColumn<string>(
    name: "FullName",
    table: "Customers",
    nullable: true);

EF Core は通常、その意図が列を削除して新しい列を作成する (2 つの個別の変更) ことなのか、列の名前を変更する必要があるのかを把握できません。 上の移行がそのまま適用されると、すべての顧客名が失われてしまいます。 列の名前を変更するには、上の生成された移行を次のように置き換えます。

migrationBuilder.RenameColumn(
    name: "Name",
    table: "Customers",
    newName: "FullName");

ヒント

移行のスキャフォールディング手順では、(列の削除など) データが失われる場合に、警告が出ます。 その警告が表示されたら、移行コードが正しいことを特に確認してください。

生 SQL の追加

組み込みの API を使用して列の名前を変更することもできますが、多くの場合は使用できません。 たとえば、既存の FirstName プロパティと LastName プロパティを 1 つの新しい FullName プロパティに置き換えるとします。 EF Core によって生成される移行は次のようになります。

migrationBuilder.DropColumn(
    name: "FirstName",
    table: "Customer");

migrationBuilder.DropColumn(
    name: "LastName",
    table: "Customer");

migrationBuilder.AddColumn<string>(
    name: "FullName",
    table: "Customer",
    nullable: true);

前と同様に、これにより望ましくないデータ損失が発生します。 古い列からデータを転送するために、移行を再編成し、次のように生 SQL 操作を導入します。

migrationBuilder.AddColumn<string>(
    name: "FullName",
    table: "Customer",
    nullable: true);

migrationBuilder.Sql(
@"
    UPDATE Customer
    SET FullName = FirstName + ' ' + LastName;
");

migrationBuilder.DropColumn(
    name: "FirstName",
    table: "Customer");

migrationBuilder.DropColumn(
    name: "LastName",
    table: "Customer");

生 SQL による任意の変更

生 SQL は、EF Core に認識されていないデータベース オブジェクを管理するためにも使用できます。 これを行うには、モデルを変更せずに移行を追加します。空の移行が生成され、そこに生の SQL 操作を設定できます。

たとえば、次の移行では、SQL Server のストアド プロシージャが作成されます。

migrationBuilder.Sql(
@"
    EXEC ('CREATE PROCEDURE getFullName
        @LastName nvarchar(50),
        @FirstName nvarchar(50)
    AS
        RETURN @LastName + @FirstName;')");

ヒント

ステートメントが SQL バッチ内の最初または唯一のものでなければならない場合は、EXEC が使用されます。 また、参照先の列が現在テーブルに存在しない場合に発生する可能性がある、べき等移行スクリプトのパーサー エラーを回避するために使用することもできます。

これを使用して、次のようなデータベースのあらゆる側面を管理できます。

  • ストアド プロシージャ
  • フルテキスト検索
  • 関数
  • トリガー
  • ビュー

ほとんどの場合、移行の適用時に、EF Core によって各移行が独自のトランザクションに自動的にラップされます。 残念ながら、一部のデータベースでは、一部の移行操作をトランザクション内で実行できません。このような場合は、suppressTransaction: truemigrationBuilder.Sql に渡してトランザクションからオプトアウトできます。

移行を削除する

移行の追加後、適用する前に EF Core モデルの追加変更が必要なことに気付く場合があります。 最後の移行を削除するには、このコマンドを使用します。

dotnet ef migrations remove

移行の削除後、追加のモデル変更を行い、もう一度追加できます。

警告

実稼働データベースに既に適用されている移行は削除しないようにしてください。 そうすることで、これらの移行をデータベースから元に戻すことができなくなり、後続の移行による想定が成り立たなくなる可能性があります。

移行の一覧表示

次のようにして、既存のすべての移行を一覧表示できます。

dotnet ef migrations list

保留中のモデル変更の確認

Note

この機能は、EF Core 8.0 で追加されました。

最後の移行以降にモデルの変更が行われたかどうかを確認したい場合があります。 これは、自分やチームメイトがいつ移行を追加し忘れたかを知るのに役立ちます。 これを行う 1 つの方法は、次のコマンドを使うことです。

dotnet ef migrations has-pending-model-changes

また、context.Database.HasPendingModelChanges() を使ってプログラムでこのチェックを実行することもできます。 これを使うと、移行を追加し忘れた場合に失敗する単体テストを記述できます。

すべての移行のリセット

一部の極端なケースでは、すべての移行を削除して最初からやり直す必要が生じる場合があります。 これは、Migrations フォルダーを削除してデータベースをドロップすることで簡単に実行できます。その時点で、現在のスキーマ全体を含む新しい初期移行を作成できます。

また、すべての移行をリセットし、データを失わずに 1 つの移行を作成することもできます。 これは "スカッシュ" と呼ばれ、いくつかの手動作業が必要になります。

  1. 問題が発生した場合に備えて、データベースをバックアップします。
  2. データベースで、移行履歴テーブルからすべての行を削除します (例: SQL Server に対して DELETE FROM [__EFMigrationsHistory])。
  3. Migrations フォルダーを削除します。
  4. 新しい移行を作成し、そのための SQL スクリプトを生成します (dotnet ef migrations script)。
  5. 1 行を移行履歴に挿入して、最初の移行が既に適用済みであることを記録します (テーブルが既にそこにあるため)。 INSERT SQL は上記で生成された SQL スクリプトの最後の操作であり、次のようになります (値を更新することを忘れないでください)。
INSERT INTO [__EFMigrationsHistory] ([MIGRATIONID], [PRODUCTVERSION])
VALUES (N'<full_migration_timestamp_and_name>', N'<EF_version>');

警告

Migrations フォルダーが削除された場合、カスタム移行コードはすべて失われます。 保存するには、カスタマイズ内容を新しい初期移行に手動で適用する必要があります。

その他のリソース