2013-03-28 5 views
10

Używam Entity Framework Code First migrations, i mam scenariusz, w którym chcę uruchomić zestaw testów integracyjnych. Za każdym razem próby uruchomienia, chcę, aby ponownie utworzyć bazę danych, i zastosować wszystkie migracjeEF 5, Code First - Utwórz nową bazę danych i uruchom wszystkie migracje programowo

Kroki powinny być:

  1. Kropla istniejąca baza danych badania (jeżeli występują)
  2. Utwórz nowy test bazy danych i zastosować wszystkie migracje
  3. dane Seed

jest to istniejący projekt, który dodałem do migracji, i użyłem enable-migracje polecenie, aby utworzyć „InitialCreate” migracji th zawiera kod, aby dodać wszystkie tabele do mojej bazy danych.

Kod w moim zwyczaju IDatabaseInitializer jest następujący:

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 metoda mojego InitialCreate migracji nie jest uzyskiwanie nazywany przez ten kod, który nie jest to, czego się spodziewałem. Zamiast tego wszystkie tabele są tworzone po wywołaniu metody Database.Create(). Potrzebuję migracji InitialCreate, ponieważ mam dodatkowy kod do tworzenia procedur składowanych.

Moje pytanie brzmi: w jaki sposób programowo utworzyć nową bazę danych i uruchomić wszystkie migracje (w tym migrację InitialCreate)?

Odpowiedz

4

Poniższy kod pozwolił mi spełnić wymagania mojego scenariusza testów integracyjnych opisane w pytaniu, ale na pewno jest lepszy sposób?

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; 
    } 
} 
1

Wystarczy usunąć krok "Utwórz bazę danych" i samodzielnie korzystać z migracji. Umieszczam przykładowy projekt na GitHub, ale ważnym bitem jest

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

foreach (string s in migrator.GetPendingMigrations()) 
{ 
    migrator.Update(s); 
}