2013-03-28 2 views
10

Sto utilizzando le migrazioni di Entity Framework Code First e ho uno scenario in cui voglio eseguire una suite di test di integrazione. Ogni volta che i test eseguiti, voglio ricreare il database, e applicare tutte le migrazioniEF 5, codice dapprima - Creare un nuovo database ed eseguire tutte le migrazioni a livello di programmazione

I passaggi dovrebbero essere:

  1. Eliminare il database di prova esistente (se presente)
  2. creare un nuovo test database e applicare tutte le migrazioni
  3. dati Seed

si tratta di un progetto esistente che ho migrazioni aggiunto a, e ho usato le Enable-migrazioni comando per creare una migrazione "InitialCreate" th contiene codice per aggiungere tutte le tabelle al mio database.

Il codice nel mio costume IDatabaseInitializer è la seguente:

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(); 
} 

Il Up metodo della mia migrazione InitialCreate non è sempre chiamato da questo codice, che non è quello che mi aspettavo. Invece, tutte le tabelle vengono create quando viene chiamato il metodo Database.Create(). Ho bisogno di eseguire la migrazione InitialCreate perché ho un codice aggiuntivo in là per creare stored procedure.

Quindi le mie domande sono, come posso creare un nuovo database a livello di codice ed eseguire tutte le migrazioni (inclusa la migrazione di InitialCreate)?

risposta

4

Il seguente codice mi ha permesso di soddisfare le esigenze del mio scenario di test di integrazione delineato nella domanda, ma sicuramente c'è un modo migliore?

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

Basta rimuovere il passaggio "crea database" e utilizzare le migrazioni autonomamente. Inserisco un progetto di esempio su GitHub, ma il bit importante è

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

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