次の方法で共有


Managing Migrations

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

Tip

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

移行を追加する

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

dotnet ef migrations add AddBlogCreatedTimestamp

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

Migrations ディレクトリの下に、次の 3 つのファイルがプロジェクトに追加されます。

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

ファイル名のタイムスタンプは、変更の進行状況を確認できるように、時系列に並べ替えるのに役立ちます。

Namespaces

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

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

Note

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

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

EF Core は通常、正確な移行を作成しますが、常にコードを確認し、目的の変更に対応していることを確認する必要があります。場合によっては、そうする必要さえある。

Column renames

移行のカスタマイズが必要な注目すべき例の 1 つは、プロパティの名前を変更する場合です。 たとえば、プロパティの名前を Name から FullName に変更すると、EF Core によって次の移行が生成されます。

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

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

通常、EF Core では、列を削除して新しい列を作成する (2 つの個別の変更)、および列の名前を変更する必要があるタイミングを知ることができません。 上記の移行が as-is適用されると、すべての顧客名が失われます。 列の名前を変更するには、上記で生成された移行を次のように置き換えます。

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

Tip

移行スキャフォールディング プロセスは、操作によってデータが失われる可能性がある場合に警告します (列の削除など)。 その警告が表示される場合は、特に移行コードの精度を確認してください。

生 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;')");

Tip

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

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

  • Stored procedures
  • Full-Text Search
  • Functions
  • Triggers
  • Views

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

移行を削除する

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

dotnet ef migrations remove

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

Warning

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

Listing migrations

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

dotnet ef migrations list

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

Note

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

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

dotnet ef migrations has-pending-model-changes

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

すべての移行のリセット

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

また、すべての移行をリセットし、データを失うことなく単一の移行を作成することもできます。 これは "スカッシュ" と呼ばれることもあります。これには手動での作業が含まれます。

  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>');

Warning

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

Additional resources