EF 5, Code First - Создайте новую базу данных и запустите все миграции программно.

Я использую миграции 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();
}

Метод Up моей миграции InitialCreate не вызывается этим кодом, чего я не ожидал. Вместо этого все таблицы создаются при вызове метода Database.Create(). Мне нужно запустить миграцию InitialCreate, потому что у меня есть дополнительный код для создания хранимых процедур.

Итак, мой вопрос: как мне программно создать новую базу данных и запустить все миграции (включая миграцию InitialCreate)?


person Matt    schedule 28.03.2013    source источник


Ответы (2)


Следующий код позволил мне удовлетворить потребности моего сценария интеграционного тестирования, изложенного в вопросе, но, конечно, есть способ лучше?

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;
    }
}
person Matt    schedule 29.03.2013

Просто удалите шаг «создать базу данных» и используйте миграции сами по себе. Я разместил образец проекта на GitHub, но важная часть -

Configuration config = new Configuration();
DbMigrator migrator = new DbMigrator(config);

foreach (string s in migrator.GetPendingMigrations())
{
    migrator.Update(s);
}
person mike mckechnie    schedule 19.09.2015