18

以下のカスタム DatabaseInitialiser があります

/// <summary>
/// Implements the IDatabaseInitializer to provide a custom database initialisation for the context.
/// </summary>
/// <typeparam name="TContext">TContext is the DbContext</typeparam>
public class ParikshaDataBaseInitializer<TContext> : IDatabaseInitializer<TContext> where TContext : DbContext
{
    /// <summary>
    /// The method to Initialise the database.
    /// Takes care of the database cannot be dropped since it is in use problem while dropping and recreating the database.
    /// </summary>
    /// <param name="context">The DbContext on which to run the initialiser</param>
    public void InitializeDatabase(TContext context)
    {
        var exists = context.Database.Exists();

        try
        {
            if (exists && context.Database.CompatibleWithModel(true))
            {
                // everything is good , we are done
                return;
            }

            if (!exists)
            {
                context.Database.Create();
            }
        }
        catch (Exception)
        {
            //Something is wrong , either we could not locate the metadata or the model is not compatible.
            if (exists)
            {
                context.Database.ExecuteSqlCommand("ALTER DATABASE Pariksha SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
                context.Database.ExecuteSqlCommand("USE Master DROP DATABASE Pariksha");
                context.SaveChanges();
            }

            context.Database.Create();
        }
    } 
}

上記のコードについての何かは単なるハック以上のものです (助けを借りて自由に参加してください)

次に、移行を追加し、移行スクリプトも正しく機能するようにしました。

    internal sealed class Configuration : DbMigrationsConfiguration<ParikshaContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
            ContextKey = "EFRepository.Context.ParikshaContext";
        }

        protected override void Seed(ParikshaContext context)
        {
        }
    }

移行は期待どおりに機能します。

さて、質問は私のアプリケーションの起動時に何をすべきですか? このようなもの

 var config = new Configuration();
 var migrator = new DbMigrator(config);
 migrator.Update();

また、一部のフォーラムでは、コンテキストを使用するたびにデータベースとスキーマが正しいかどうかを確認したくないため、少し奇妙に思えるコンストラクターでもこれを提案しました。それで、このテクニックの可能な使用法は何ですか、または提案のコンテキストが間違っていると思いましたか?

public ParikshaContext() : base("Pariksha")
        {           
          Database.SetInitializer(new ParikshaDataBaseInitializer<ParikshaContext>());
        }

要約すると、

  1. 利用可能なさまざまな手法の正しいユースケースは何ですか?

  2. 移行がすべての条件で機能し、データベースをある環境から別の環境に移動するときに理想的な戦略は何でしょうか?

4

2 に答える 2

12

これは、イニシャライザとデフォルトの両方をシードとDb Initializer組み合わせた私の試みです。(注:理想的ではなく、単純な演習に似ていますが、ここで求めていることの解決策を提供します。ほとんどの場合、私が行ったすべての更新を確認してください)。 MigrationDb Create

mysql データベースを作成および移行するための初期化子を作成する方法は?

whyおよび- EFソースコードhowも参照することをお勧めすることを完全に理解するために(これは新しいバージョンですが、多くの点で似ています)

1)

a)DB初期化子は通常、(接続ごとに)1回だけ呼び出されます-「モデル」に初めてアクセスしようとしたとき(最初のクエリなど)。チェックするイニシャライザにブレークポイントを設定します。

したがって、コンストラクター内に配置することは完全に安全です(ただし、どこかで起動することを好みますが、構成も同様です)。初期化が必要な場合(およびlast one setが使用された場合) にのみ呼び出されます。手動で呼び出すべきではありません。

とにかく、イニシャライザを強制するには、次のことができますthis.Database.Initialize(force: true);

接続を切り替えるときは、問題に関する私の投稿を参照してください
IDbContextFactory を使用せずに最初のカスタム接続文字列と移行をコーディングします

b)独自のものを作成し、IDatabaseInitializerそれでも移行を機能させたい場合side by side

DbMigratorカスタムイニシャライザが「データベースの作成」全体を見逃すため、外部から呼び出すだけではいけません(たとえば、シードなどを行いたい場合は、上記の例を確認してください)。

両方とも事実上「初期化子」であるため、それらを 1 つに統合する必要がありますchain。重要なことを覚えておいてorder of executionください(問題については上記の例を参照してください)-「空の状態」を確認してから、を呼び出しDbMigratorてから、独自の初期化を行う必要があります。1 つの初期化子を基本クラスとして使用し、もう 1 つをマージしました。

必要に応じてseed、移行構成を使用できます。これは、もっともらしい場合に最も簡単です。

2)

かなり「オープンエンド」であり、単一の答えはありません。通常は機能しますが、問題が予想されます...

  • __MigrationHistory移行は、コード モデル/エンティティ、データベース/テーブル、およびデータベース内のシステム テーブルの3 つです (私が見ているように) 。3つすべてが滞在する必要がありますin sync。「非同期」になった場合は、移行テーブルを削除し、移行を再作成して (既存のデータベースを保持するためのフラグを使用)、以前と同様に続行できます。つまり、ライブ データを使用する場合の解決策があります。これについては、「EF 4.3 移行でテーブル/クラスを無視する方法」を参照 してください。

  • データベースを移動するときに Db を削除/作成する権限が必要です。

  • 接続が正しいことを確認してください(構成の変更-およびDbContext名またはctorと同期しています)、

  • シンプルに保ち、派手なことをしたり、コードから接続を切り替えたりしないでください(可能ですが問題があります)など、

  • バージョンを作成しないでくださいmix database / code- つまり、1 つのコード エンティティ バージョン - 1 つのデータベースです。同じ Db を異なるコード バージョン (ステージング、運用など) と共有する場合は、共有しないでください (マルチテナント ソリューションは EF6 で利用できます - 例: this )。

  • データベースを手動で適用する必要がある場合 -scriptビアを生成し、Update-Databaseそれを適用します。手動で行わないでください。そうしないと、間違ってしまいます (移行履歴テーブル) -これを参照してください。

...それはほんの数例です。それは非常に安定しており、使用可能な IMO ですが、ルールに従っていれば、制限が何であるかを知っている必要があります。


class CreateAndMigrateDatabaseInitializer<TContext, TConfiguration> 
    : CreateDatabaseIfNotExists<TContext>, IDatabaseInitializer<TContext>
    where TContext : DbContext
    where TConfiguration : DbMigrationsConfiguration<TContext>, new()
{
    private readonly DbMigrationsConfiguration _configuration;
    public CreateAndMigrateDatabaseInitializer()
    {
        _configuration = new TConfiguration();
    }
    public CreateAndMigrateDatabaseInitializer(string connection)
    {
        Contract.Requires(!string.IsNullOrEmpty(connection), "connection");

        _configuration = new TConfiguration
        {
            TargetDatabase = new DbConnectionInfo(connection)
        };
    }
    void IDatabaseInitializer<TContext>.InitializeDatabase(TContext context)
    {
        var doseed = !context.Database.Exists();
        // && new DatabaseTableChecker().AnyModelTableExists(context);
        // check to see if to seed - we 'lack' the 'AnyModelTableExists'
        // ...could be copied/done otherwise if needed...

        var migrator = new DbMigrator(_configuration);
        // if (doseed || !context.Database.CompatibleWithModel(false))
        if (migrator.GetPendingMigrations().Any())
            migrator.Update();

        // move on with the 'CreateDatabaseIfNotExists' for the 'Seed'
        base.InitializeDatabase(context);
        if (doseed)
        {
            Seed(context);
            context.SaveChanges();
        }
    }
    protected override void Seed(TContext context)
    {
    }
}
于 2013-04-21T23:47:31.203 に答える
4

要約すると、

1) what is the correct use-case for the different techniques available ?

2) what would be the ideal strategy so that the migrations work in all conditions 
and when we move databases from one environment to another ?

一歩下がって、いつ EF に初期化と移行を実行させたいか自問してください。私の (エンタープライズ) 組織では、コード、データ、および DDL の移行方法について非常に厳格なルールがあるため、これらの機能には何の価値もありません。たとえ使用できたとしても、さまざまな環境でツールを使用してかなりの経験を積むまで、私は非常に用心深いでしょう.

それで、なぜそれを使うのですか?あなたは新しいグリーン フィールド プロジェクトを開始しており、コード ファーストを使用しています。さて、ここが役に立つところです。コードを記述し、コンパイルして実行し、EF に新しいフィールド、欠落しているフィールド、リレーションシップ、およびテーブルについて心配させることができます。後で、開発サーバーでそれを形式化し、初期化子と移行子を永久に削除できます。

設定方法は?うまくいく方法を見つけたようです。少しハッキーに見えることに同意しますが、コードは私の初期設定と似ています。私は MVC.NET を使用しているため、Global.asax.cs で以下を使用しました。

 Database.SetInitializer(new DomainInitializer());

結論は、あなたの(2)は間違った質問だと思います。「本当にこうしていいの?」というはずです。そうなるかもしれませんが、特に 10 人以上の会社に所属している場合は、他のより伝統的なオプションを最初に検討することをお勧めします。

于 2013-04-22T23:29:42.497 に答える