web-dev-qa-db-ja.com

EF自動移行とシードに関する混乱-すべてのプログラム開始のシード

私は最近、devに以下を使用するようにアプリケーションを変更しました:

DropCreateDatabaseIfModelChanges<Context>


使用するには:

public class MyDbMigrationsConfiguration: DbMigrationsConfiguration<GrsEntities>
{
    public MyDbMigrationsConfiguration()
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = true;
    }
}


私のdbコンテキストでは、

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Tell Code First to ignore PluralizingTableName convention
    // If you keep this convention then the generated tables will have pluralized names.
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

    //set the initializer to migration
    Database.SetInitializer(new MigrateDatabaseToLatestVersion<GrsEntities, MigrationConfig>());
}

AddOrUpdate拡張機能を使用してDbMigrationsConfigurationのSeed(context)をオーバーライドしましたが、ドロップデータベース(DropCreateDatabaseIfModelChanges)にシードする前にAddを使用していました。

私の混乱は、DbContextに変更があるかどうかに関係なく、アプリケーションの起動ごとにMigrationが実行されることです。アプリケーションを起動するたびに(サービスを介して実行されるライブラリ)、イニシャライザはシードと同じように実行されます。私の予想される動作は、移行が必要かどうかのチェック(モデルが物理データベースと一致するかどうかを確認する舞台裏で)であり、新しい/削除されたテーブル/列を更新し、何かが変更された場合にのみシードを実行します。

私のテストでは、シードは毎回実行されます。これは実行可能ですが、一見効率が悪く、期待したものではありませんでした。残念ながら、MSDNのドキュメントはかなり制限されています。

MigrateDatabaseToLatestVersionを完全に誤用していますか?私が期待する動作(つまり、モデルが変更された場合にのみシード)を取得する方法はありますか?または、アプリケーションの起動ごとに実行されるようにシードメソッドを変更する必要がありますか?

42
shox

Seedメソッドがデータベースが変更されたときにのみ実行されるという事実は、EF 4.1で出荷されたデータベースイニシャライザをかなり制限していました。データベースを変更せずにシードデータを更新する必要がある場合があるため、しかし、それを実現するには、データベースが変更されたように見せかける必要があります。

Migrationsを使用すると、Seedの使用が少し異なりました。これは、データベースが空であると想定できなくなったためです。つまり、それがMigrationsのポイントのようなものです。つまり、Seedメソッドは、データベースが存在し、すでにデータが含まれていると想定する必要がありますが、Migrationsのデータベースに加えられた変更を考慮するために、データを更新する必要がある場合があります。したがって、 AddOrUpdate。

つまり、Seedは既存のデータを考慮に入れて記述する必要があります。つまり、実際にEF 4.1の制限を永続化する必要がないということですSeedメソッドを実行するために、データベースが変更されたように見えるようにする必要がありますSeedを実行します。したがって、Seedアプリドメインでコンテキストが初めて使用されるとき。これにより、Seedはデータが既に存在する場合に対処する必要があるため、実装される方法は変更されません。

Seedデータが多いためにパフォーマンスの問題が発生する場合は、通常、データベースにクエリを実行してSeedメソッドにチェックを追加することは簡単ですそれを行う前にどれだけの作業を行う必要があるか。

61
Arthur Vickers

Arthur Vickers 応答には多少同意しますが、IMO SeedはDbMigrations用であり、Seedメソッドが毎回すべてをチェックすることを望んでいません。 4つの移行がある場合、シードする必要のあるデータを何らかの方法でテストする必要があります。これは、少なくとも4つのデータベースヒットになります。私のように、マイグレーションが適用された場合にのみSeedメソッドを実行する動作が必要な場合は、IDatabaseInitializer戦略の独自の実装が付属しています

public class CheckAndMigrateDatabaseToLatestVersion<TContext, TMigrationsConfiguration>
    : IDatabaseInitializer<TContext>
    where TContext : DbContext
    where TMigrationsConfiguration : DbMigrationsConfiguration<TContext>, new()
{
    public virtual void InitializeDatabase(TContext context)
    {
        var migratorBase = ((MigratorBase)new DbMigrator(Activator.CreateInstance<TMigrationsConfiguration>()));
        if (migratorBase.GetPendingMigrations().Any())
            migratorBase.Update();
    }
}
18

別のオプションは、実行時にシードメソッド内でカスタムdb初期化子クラスをロードすることです。本番アプリはダミーの初期化子をロードでき、開発アプリは実際の初期化子をロードできます。 Unity/MEFを使用できます

    // Unity Dependency Injection Prop
    [Dependency]
    property IMyInitializer initializer;

    protected override Seed(YourContextClass context)
    {
       initializer.Seed(context);
    }

そんな感じ。本番環境でDBをセットアップしたら、初期化子をダミーのイニシャライザに切り替えます。ダミーは何もしません。

2