10

Entity Framework Code First の移行を使用しており、一連の統合テストを実行するシナリオがあります。テストを実行するたびに、データベースを再作成し、すべての移行を適用したい

手順は次のとおりです。

  1. 既存のテスト データベースを削除します (存在する場合)。
  2. 新しいテスト データベースを作成し、すべての移行を適用します
  3. シードデータ

これは、移行を追加した既存のプロジェクトです。Enable-Migrations コマンドを使用して、データベースにすべてのテーブルを追加するコードを含む「InitialCreate」移行を作成しました。

私のカスタムのコードはIDatabaseInitializer次のとおりです。

public void InitializeDatabase(MyContext context)
{
    //delete any existing database, and re-create
    context.Database.Delete();
    context.Database.Create();            

    //apply all migrations
    var dbMigrator = new DbMigrator(new Configuration());
    dbMigrator.Update();

    //seed with data
    this.Seed(context);

    context.SaveChanges();
}

私の InitialCreate 移行のUpメソッドは、このコードによって呼び出されません。これは私が期待したものではありません。Database.Create()代わりに、メソッドが呼び出されると、すべてのテーブルが作成されます。ストアド プロシージャを作成する追加のコードがあるため、InitialCreate 移行を実行する必要があります。

私の質問は、プログラムで新しいデータベースを作成し、すべての移行 (InitialCreate 移行を含む) を実行するにはどうすればよいですか?

4

2 に答える 2

5

次のコードにより、質問で概説されている統合テスト シナリオのニーズを満たすことができましたが、もっと良い方法はありますか?

public void InitializeDatabase(MyContext context)
{
    //delete any existing database, and re-create
    context.Database.Delete();

    var newDbConnString = context.Database.Connection.ConnectionString;
    var connStringBuilder = new SqlConnectionStringBuilder(newDbConnString);
    var newDbName = connStringBuilder.InitialCatalog;

    connStringBuilder.InitialCatalog = "master";

    //create the new DB
    using(var sqlConn = new SqlConnection(connStringBuilder.ToString()))
    {
        using (var createDbCmd = sqlConn.CreateCommand())
        {
            createDbCmd.CommandText = "CREATE DATABASE " + newDbName;
            sqlConn.Open();
            createDbCmd.ExecuteNonQuery();
        }
    }

    //wait up to 30s for the new DB to be fully created
    //this takes about 4s on my desktop
    var attempts = 0;
    var dbOnline = false;
    while (attempts < 30 && !dbOnline)
    {
        if (IsDatabaseOnline(newDbConnString))
        {
            dbOnline = true;
        }
        else
        {
            attempts++;
            Thread.Sleep(1000);
        }
    }

    if (!dbOnline)
        throw new ApplicationException(string.Format("Waited too long for the newly created database \"{0}\" to come online", newDbName));

    //apply all migrations
    var dbMigrator = new DbMigrator(new Configuration());
    dbMigrator.Update();

    //seed with data
    this.Seed(context);

    context.SaveChanges();
}

private bool IsDatabaseOnline(string connString)
{
    try
    {
        using (var sqlConn = new SqlConnection(connString))
        {
            sqlConn.Open();
            return sqlConn.State == ConnectionState.Open;
        }
    }
    catch (SqlException)
    {
        return false;
    }
}
于 2013-03-29T00:01:25.473 に答える