データのシード処理

データ シーディングは、データベースに初期データ セットを設定するプロセスです。

EF Core では、次のいくつかの方法で実現できます。

  • モデル シード データ
  • 手動による移行のカスタマイズ
  • カスタム初期化ロジック

モデル シード データ

EF6 とは異なり、EF Core ではシード用データをモデル構成の一部としてエンティティ型に関連付けることができます。 EF Core の移行では、データベースをモデルの新しいバージョンにアップグレードするときに、挿入、更新、または削除のどの操作を適用する必要があるかを自動的に計算できます。

Note

移行では、シード データを目的の状態にするために実行する操作を決定する際に、モデルの変更のみを考慮します。 そのため、移行の外部で実行されたデータの変更が失われたり、エラーの原因になったりする可能性があります。

例として、これによって OnModelCreatingBlog のシード データが構成されます。

modelBuilder.Entity<Blog>().HasData(new Blog { BlogId = 1, Url = "http://sample.com" });

リレーションシップを持つエンティティを追加するには、外部キーの値を指定する必要があります。

modelBuilder.Entity<Post>().HasData(
    new Post { BlogId = 1, PostId = 1, Title = "First post", Content = "Test 1" });

エンティティ型のプロパティがシャドウ状態の場合、匿名クラスを使用して値を指定できます。

modelBuilder.Entity<Post>().HasData(
    new { BlogId = 1, PostId = 2, Title = "Second post", Content = "Test 2" });

所有エンティティ型も、同様の方法でシード処理できます。

modelBuilder.Entity<Post>().OwnsOne(p => p.AuthorName).HasData(
    new { PostId = 1, First = "Andriy", Last = "Svyryd" },
    new { PostId = 2, First = "Diego", Last = "Vega" });

詳細なコンテキストについては、完全なサンプル プロジェクトに関するページを参照してください。

データがモデルに追加されたら、移行を使用して変更を適用する必要があります。

ヒント

自動展開の一部として移行を適用する必要がある場合は、実行前にプレビューできる SQL スクリプトを作成できます。

または、context.Database.EnsureCreated() を使用して、シード データを含む新しいデータベースを作成することができます。たとえば、テスト データベースの場合や、メモリ内プロバイダーまたはリレーショナル データベース以外を使用する場合があります。 データベースが既に存在する場合、EnsureCreated() ではスキーマもデータベース内のシード データも更新されないことに注意してください。 リレーショナル データベースの場合、移行を使用する予定がある場合は、EnsureCreated() を呼び出さないでください。

モデル シード データの制限事項

この種類のシード データは、移行によって管理されます。また、データベースに既に存在するデータを更新するためのスクリプトは、データベースに接続せずに生成する必要があります。 これによって、いくつかの制限が課されます。

  • 主キーの値は、通常はデータベースによって生成される場合でも、指定する必要があります。 移行間のデータ変更を検出するために使用されます。
  • 以前にシードされたデータは、主キーが何らかの方法で変更されると削除されます。

したがって、この機能は移行の外部で変更されることが想定されておらず、データベース内の他のものに依存しない、郵便番号などの静的データに対して最も役立ちます。

シナリオに以下のいずれかが含まれている場合は、最後のセクションに記載されているカスタム初期化ロジックを使用することをお勧めします。

  • テスト用の一時データ
  • データベースの状態に依存するデータ
  • サイズの大きいデータ (シード用データは移行スナップショットでキャプチャされ、大きなデータはすぐに非常に大きなファイルになり、パフォーマンスが低下する可能性があります)。
  • データベースによって生成されるキー値を必要とするデータ (代替キーを ID として使用するエンティティなど)
  • 一部のパスワード ハッシュなど、(値の変換によって処理されない) カスタム変換を必要とするデータ
  • 外部 API の呼び出しを必要とするデータ (ASP.NET Core ID ロールやユーザーの作成など)

手動による移行のカスタマイズ

移行が追加されると、HasData で指定したデータに加えた変更が、InsertData()UpdateData()、および DeleteData() の呼び出しに変換されます。 HasData の制限事項を回避する方法の 1 つとして、これらの呼び出しまたはカスタム操作を移行に手動で追加することがあります。

migrationBuilder.InsertData(
    table: "Blogs",
    columns: new[] { "Url" },
    values: new object[] { "http://generated.com" });

カスタム初期化ロジック

データのシード処理を実行するための簡単で強力な方法は、メインのアプリケーション ロジックの実行が開始される前に DbContext.SaveChanges() を使用することです。

using (var context = new DataSeedingContext())
{
    context.Database.EnsureCreated();

    var testBlog = context.Blogs.FirstOrDefault(b => b.Url == "http://test.com");
    if (testBlog == null)
    {
        context.Blogs.Add(new Blog { Url = "http://test.com" });
    }

    context.SaveChanges();
}

警告

シード処理コードは、複数のインスタンスが実行されるときにコンカレンシーの問題の原因となる可能性があり、データベース スキーマを変更するアクセス許可をアプリに持たせることも必要になるため、通常のアプリの実行には含めないでください。

展開の制約に応じて、初期化コードはさまざまな方法で実行できます。

  • 初期化アプリをローカルで実行する
  • メイン アプリと一緒に初期化アプリをデプロイし、初期化ルーチンを呼び出し、初期化アプリを無効化または削除する

これは通常、発行プロファイルを使用して自動化できます。