2013-03-28 13 views
10

Ich verwende Entity Framework Code Erste Migrationen, und ich habe ein Szenario, in dem ich eine Reihe von Integrationstests ausführen möchte. Jedes Mal, wenn die Tests durchführen, möchte ich die Datenbank neu erstellen, und wenden Sie alle MigrationenEF 5, Code First - Erstellen Sie eine neue Datenbank und führen Sie alle Migrationen programmatisch durch

Die Schritte sein sollten:

  1. Tropfen die vorhandene Testdatenbank (falls vorhanden)
  2. Erstellen Sie einen neuen Test Datenbank und gelten alle Migrationen
  3. Seed Daten

Dies ist ein vorhandenes Projekt, das ich hinzugefügt haben Migrationen, und ich benutzte die Enable-Migrations-Befehl eine „InitialCreate“ Migration erstellen th at enthält Code, um alle Tabellen zu meiner Datenbank hinzuzufügen.

Der Code in meine Gewohnheit ist IDatabaseInitializer wie folgt:

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

Die Up Methode meiner InitialCreate Migration wird von diesem Code aufgerufen zu werden, die nicht das, was ich erwartet hatte. Stattdessen werden alle Tabellen erstellt, wenn die Methode aufgerufen wird. Ich brauche die InitialCreate-Migration, um ausgeführt zu werden, da ich dort zusätzlichen Code zum Erstellen gespeicherter Prozeduren habe.

Also meine Fragen ist, wie programmiere ich programmatisch eine neue Datenbank und führen Sie alle Migrationen (einschließlich der InitialCreate Migration)?

Antwort

4

Der folgende Code ermöglicht es mir, die Anforderungen meines in der Frage beschriebenen Integrationstestszenarios zu erfüllen, aber sicherlich gibt es einen besseren Weg?

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

Entfernen Sie einfach den Schritt "create database" und verwenden Sie die Migrationen eigenständig. Ich legte ein Beispielprojekt auf GitHub, aber das wichtige Bit ist

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

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