2013-10-21 18 views
12

In EF5, ho fatto valere il fatto che ho potuto ricreare il mio database dal modello utilizzando Database.CreateIfNotExists()Come si genera un database EF6 con le migrazioni abilitate, senza utilizzare database di aggiornamento?

vorrei generare migrazioni come necessario, ma mai il check-in al controllo del codice sorgente (in quanto tendevano ad essere artefatti dello sviluppo ciclo) Ogni sviluppatore eliminerebbe e ricreare i propri database, dal modello in base alle esigenze.

Quindi, dovremmo generare migrazioni confrontando i rami del nostro codice e ottenere l'SQL, da applicare alla produzione o ad altri database condivisi.

Questo flusso di lavoro sembra non funzionare più, poiché non è possibile generare un database da zero quando le migrazioni sono abilitate, senza prima generare tutte le migrazioni e quindi chiamare update-database. Dato che chiamare add-migration modifica il file csproj, ciò rende inutilizzabili i miei script (che ci consentono di cambiare facilmente i rami).

Le migrazioni sono abilitate per il contesto 'ApplicationDbContext' ma il database non esiste o non contiene tabelle associate. Utilizzare Migrazioni per creare il database e le relative tabelle, ad esempio eseguendo il comando "Aggiorna database" dalla console di Gestione pacchetti.

C'è un modo per ripristinare il comportamento EF5 in cui Database.Create creerà la versione corrente del db?

+2

Sembra che non ci sia una risposta ovvia a questo al momento. L'ho aggiunto come un [problema su CodePlex] (https://entityframework.codeplex.com/workitem/2022) Si prega di votare lì se si desidera vederlo corretto. – Doug

risposta

2

questo funziona per me (finora ...):

var connectionString = "Data Source=localhost;Initial Catalog=Chilli;" + 
    "Integrated Security=True;" + 
    "MultipleActiveResultSets=True;Application Name=ChilliDesktop"; 

//ooops... you have to create a new, blank database if one does not exist 
var bld = new SqlConnectionStringBuilder(connectionString); 
var dbName = bld.InitialCatalog; //i.e. Chilli 

bld.InitialCatalog = "master"; 

//a connectionstring pointing at Master 
var masterConnectionString = bld.ConnectionString; 

using (var cnn = new SqlConnection(masterConnectionString)) 
{ 
    var cmdString = string.Format(
    "if not exists (select * from sys.databases where name='{0}')" + 
    "\r\ncreate database {0}", 
    dbName); 
    using (var cmd = new System.Data.SqlClient.SqlCommand(cmdString,cnn)) 
    { 
    cmd.Connection.Open(); 
    cmd.ExecuteNonQuery(); 
    }     
} 


var connectionInfo = 
    new System.Data.Entity.Infrastructure 
     .DbConnectionInfo(connectionString, "System.Data.SqlClient"); 
//new up your auto-created Migrations Configuration class 
var config = new Chilli.Context.Migrations.Configuration(); 
config.TargetDatabase = connectionInfo; 
//new up a Migrator 
var migrator = new System.Data.Entity.Migrations 
    .DbMigrator(config); 
migrator.Update(); 
//you now have a database 

//run your Seed method 
using (var dc = new Chilli.Context.Context(connectionString)) 
{ 
    Chilli.Context.ChilliContextInitializerHelper.Seed(dc); 
} 

http://softwaremechanik.wordpress.com/2013/11/04/ef6-if-migrations-are-enabled-cannot-createdatabaseifnotexists/

+0

Appena realizzato, è necessario creare un nuovo database vuoto prima di chiamare Update() – ajd

+0

Hi @ dannykay1710: per il controllo granulare delle migrazioni, ottenere un elenco di Migrazioni in attesa quindi applicare solo alcune di esse ... var migrator = new System.Data .Entity.Migrations .DbMigrator (config); var pendingMigrations = migrator.GetPendingMigrations(); – ajd

12

usavo CreateDatabaseIfNotExists per inizializzare il DB e potuto usare update-base di dati ed eseguire la mia applicazione e creerebbe il DB se non esistesse già. Questo sembra essersi rotto con EF 6.0.x.

This was useful, but not what I used.

Quello che ho fatto è stato abbandonato il mio codice inizializzare esistente e lo ha sostituito con il seguente codice in Global.asax.

Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>()); 
     using (MyContext temp = new MyContext()) 
     { 
      temp.Database.Initialize(true); 
     } 

Nota: myContext è il contesto che uso e configurazione è il file di configurazione che si crea quando le migrazioni sono abilitati.

Ho visto molti post in cui le persone hanno problemi a riguardo, ma non molte che descrivono una soluzione. Non sono sicuro che il motivo per cui così tante persone, me compreso, hanno perso questo cambiamento di rottura ... (Se c'è una descrizione di questo da qualche parte, non ho mai visto prima che fosse troppo tardi.)

Edit:

Questo è il codice che ho aggiunto alla mia classe di contesto. Non mi piace tanto quanto funzionava, ma per adesso ha il compito di farcela. Vedi il commento di @ Doug all'OP sulla votazione su CodePlex.

private static readonly Object syncObj = new Object(); 
public static bool InitializeDatabase() 
{ 
    lock (syncObj) 
    { 
     using (var temp = new TbdContext()) 
     { 
      ObjectContext oc = null; 
      try 
      { 
       oc = temp.ObjectContext; 
      } 
      catch (Exception ex) 
      { 
       //Ignore error 
       Console.WriteLine(ex); 
      } 

      if (oc != null && oc.DatabaseExists()) 
      { 
       return true; 
      } 
      Database.SetInitializer(new MigrateDatabaseToLatestVersion<TbdContext, Configuration>()); 
      try 
      { 
       temp.Database.Initialize(true); 
       return true; 
      } 
      catch (DataException ex) 
      { 

     } 
    } 
} 

Quindi nel mio Global.asax.cs Application_Start() faccio questo:

if (databaseInitialized == false) 
    databaseInitialized = MyContext.InitializeDatabase(); 

Edit:.

ho aggiornato a EF 6.1 e trovato questo non funziona più (https://stackoverflow.com/a/22770517/2033294) Ecco quello che ho fatto per risolvere il problema:

private static readonly Object syncObj = new Object(); 
    public static bool InitializeDatabase() 
    { 
     lock (syncObj) 
     { 
      using (var temp = new MyContext()) 
      { 
       if (temp.Database.Exists()) return true; 

       var initializer = new MigrateDatabaseToLatestVersion<MyContext, Configuration>(); 
       Database.SetInitializer(initializer); 
       try 
       { 
        temp.Database.Initialize(true); 
        return true; 
       } 
       catch (Exception ex) 
       { 
        //Handle Error in some way 
        return false; 
       } 
      } 
     } 
    } 
+1

Il problema con questo è che migrerà il tuo database da una versione precedente a una nuova versione ... non è una corrispondenza completa per CreateDatabaseIfNotExists che crea l'ultima versione del tuo DB solo quando un DB con lo stesso nome non lo fa Esistono Voglio un controllo più granulare sulle migrazioni quando ho dati reali nel database – dannykay1710

+0

@ dannykay1710, non sono sicuro di seguirti, ma mi piacerebbe. Due domande Innanzitutto, cosa intendi per migrare a una nuova versione? Questo eseguirà le migrazioni del database stai dicendo che CreateDatabaseIfNotExists avrebbe eseguito solo le migrazioni se il DB non esisteva? Secondo, qual è un esempio di controllo granulare che vorresti/hai bisogno? – Jeff

+0

Non mi piace l'idea che un'app che ho compilato apporterà automaticamente modifiche allo schema al mio database live senza avviso, solo perché la nuova versione ha una nuova migrazione. Voglio solo che lo schema venga creato automaticamente se il DB configurato non esiste, non quando c'è una nuova migrazione. Le modifiche allo schema possono facilmente causare la perdita di dati. Mentre puoi chiedere a EF di non apportare modifiche in caso di perdita di dati, nella maggior parte dei casi, comunque, vorrei che il controllo testasse e controllasse questo cambiamento. – dannykay1710

2

Ecco la risposta ...

EF squadra Triage: Questo è 'By design' ed è stato un cambiamento intenzionale abbiamo preso in EF6. Se questo inizializzatore viene utilizzato per creare il database, viene aggiunta una singola voce alla tabella __MigrationsHistory che quindi rende il database non utilizzabile con le migrazioni (poiché questi inizializzatori non utilizzano le migrazioni per creare il database). Questo ha confuso un gran numero di persone nelle versioni precedenti, quindi abbiamo deciso di non creare automaticamente database/schema quando le migrazioni sono abilitate.

È possibile utilizzare l'inizializzatore MigrateDatabaseToLatestVersion se si desidera semplicemente applicare le migrazioni. Se si desidera eliminare il database, è possibile ricondurlo facilmente in un inizializzatore personalizzato che include una chiamata a context.Database.Delete().

http://entityframework.codeplex.com/workitem/1689

+0

Grazie per il chiarimento – mac10688

1

Per gli altri bloccati. Ho finito per farlo in EF6.

public CatContext(bool forcePreparation) 
{ 
    if (!forcePreparation) 
     return; 

    if (!Database.Exists() || !Database.CompatibleWithModel(false)) 
    { 
     Database.SetInitializer<CatContext>(new MigrateDatabaseToLatestVersion<CatContext, Configuration>()); 
    } 
    else 
    { 
     // Database exists and matches the current model. 
     // Doing this special thing to avoid the bug that arises sometimes. 
     Database.SetInitializer<CatContext>(null); 
    } 

    Database.Initialize(true); 
} 

public CatContext() 
    : this(forcePreparation: false) 
{ } 

Nel mio codice ho creare l'oggetto contesto come new CatContext(true).

Problemi correlati