42

最近、アプリケーションを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>());
}

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

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

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

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

4

3 に答える 3

61

Seedメソッドがデータベースが変更されたときにのみ実行されるという事実は、EF4.1で出荷されたデータベース初期化子にとって非常に制限的でした。データベースを変更せずにシードデータを更新する必要がある場合があるため、制限がありましたが、それを実現するには、データベースが変更されたように人為的に見せなければなりませんでした。

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

これで、既存のデータを考慮してSeedを作成する必要がある状況になりました。つまり、データベースが変更されたように見せかける必要があるように、EF4.1Seedメソッドの制限を永続化する必要はありません。シードを実行するためだけに。したがって、シードは、コンテキストがアプリドメインで初めて使用されるたびに実行されるようになりました。とにかくデータがすでに存在する場合を処理する必要があるため、これによってシードの実装方法が変わることはありません。

シードデータが多いためにパフォーマンスの問題が発生する場合は、通常、データベースにクエリを実行するチェックをシードメソッドに追加して、実行する前に実行する必要のある作業量を決定するのは簡単です。

于 2012-05-31T00:39:07.230 に答える
18

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();
    }
}
于 2015-01-16T19:23:50.627 に答える
2

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

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

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

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

于 2012-10-14T12:41:03.680 に答える