Entity Framework Coreで移行コードをカスタマイズする方法
2023-01-04
azblob://2023/01/04/eyecatch/2023-01-04-entity-framework-core-customize-migration-code-000.jpg

こんにちは、あおいです。
今年の初詣は大須観音に行ってきました!引いたおみくじが大吉!幸先のよいスタートです!

さて、EF Coreを用いたCode First開発は非常に便利です。

以下のコマンド実行をすると、[Migrations]ディレクトリの下で3つのファイルがプロジェクトに自動生成されます。

dotnet ef migrations add <Migration名>
  • XXXXX_AddCreatedAt.cs -- 移行コード
  • XXXXX_AddCreatedAt.Designer.cs -- 移行のメタデータファイル
  • DbContextModelSnapshot.cs -- 現在のモデルのスナップショット


以下のコマンドを実行すると、移行コードの内容がDBに適用されます。

dotnet ef database update

ここで大事なのが、移行コードの中身をきちんと確認しないと爆死事故が起きます。

その事故を回避するには、移行コードをスクラッチでカスタマイズする必要があります。

そこで、今回はEntity Framework Core で移行コードをカスタマイズする方法について紹介したいと思います。

例として列名(Name⇒FullName)と桁数(10⇒15)を変更すると、EF Core によって次の移行が生成されます。
Upメソッドは変更の差分をDBに適用し、Downメソッドは変更の差分を元に戻したい時に呼ばれるメソッドです。

C#using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace EFCoreSample.Migrations
{
    public partial class second : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropColumn(
                name: "Name",
                table: "Employees");

            migrationBuilder.AddColumn<string>(
                name: "FullName",
                table: "Employees",
                type: "nvarchar(15)",
                nullable: false,
                defaultValue: "");
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropColumn(
                name: "FullName",
                table: "Employees");

            migrationBuilder.AddColumn<string>(
                name: "Name",
                table: "Employees",
                type: "nvarchar(10)",
                nullable: false,
                defaultValue: "");
        }
    }
}

ここで注意しなければならない点は、上記のファイル(移行コード)をそのままマイグレーションで適用すると、既存のNameカラムにあったデータが全て失われてしまうことです。
また、列の順番も変わってしまい、元に戻そうとDownを適用(ロールバック)してもデータは復元されません。


理由はDropColumn(列を削除)して、AddColumn(新しい列を作成)するからです。そのまんまの意味です。
列を新規追加する場合は問題ないですが、既存の列定義を変更しただけで既存のデータが全部消えるのは避けたいですよね。



解決策として、以下のように移行コードをスクラッチでカスタマイズする必要があります。

C#using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace EFCoreSample.Migrations
{
    public partial class second : Migration
    {
     // dotnet ef database updateでUpメソッドが適用される
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            // 列の名前を変更して
            migrationBuilder.RenameColumn(
                name: "Name",
                table: "Employees",
                newName: "FullName");
         
       // 文字列長等の定義を変更する
            migrationBuilder.AlterColumn<string>(
                name: "FullName",
                table: "Employees",
                type: "nvarchar(15)",
                nullable: false,
                defaultValue: "",
                oldType: "nvarchar(10)",
                oldClrType: typeof(string));
        }

        // dotnet ef database update <Migration名>のロールバックでDownメソッドが適用される
        protected override void Down(MigrationBuilder migrationBuilder)
        {
       // 列の名前を元に戻して
            migrationBuilder.RenameColumn(
                name: "FullName",
                table: "Employees",
                newName: "Name");

            // 文字列等の定義を元に戻す
            migrationBuilder.AlterColumn<string>(
                name: "Name",
                table: "Employees",
                type: "nvarchar(10)",
                nullable: false,
                defaultValue: "",
                oldType: "nvarchar(15)",
                oldClrType: typeof(string));
        }
    }
}

MigrationBuilderクラスのメソッド一覧 | Microsoft Docs


 

データが失われる場合、以下の緑色の警告文が表示されます。こいつが表示されたら要注意なので、移行コードをきちんと確認するようにしましょう。


 

また、組み込みAPIが使用不可の場合、生SQL操作を導入します。
詳細についてはこちらの記事をご覧ください。


 

今回はEntity Framework Coreで移行コードをカスタマイズする方法について紹介させていただきました。
PK定義の変更をする場合も、移行コードをスクラッチでカスタマイズする必要がありますが、次回の記事で紹介します。
Entity Framework CoreでPK定義の変更をする方法 | cloud.config Tech Blog
 

参考記事
移行コードをカスタマイズする - EF Core | Microsoft Docs