2015-11-30 16 views
14

Sono su un progetto in cui stiamo utilizzando Code First su Entity Framework per il nostro database.Creazione programmatica di prime migrazioni

Vogliamo cambiare tutta la nostra continua integrazione per consumare un pacchetto MSI generato a valle, ma con EF che presenta alcune complicazioni.

  • quando il modello cambia, dobbiamo generare una migrazione basata su codice altrimenti il ​​pacchetto si romperà (Database vs Model)
  • Noi preferiamo rimuovere la creazione delle migrazioni dal team (sulla base di https://msdn.microsoft.com/en-us/data/dn481501.aspx)

ho provato varie cose dal web, ma la maggior parte sembrano richiedere AutomaticMigrations da impostare per true così come AutomaticMigrationDataLossAllowed (vedi: http://romiller.com/2012/02/09/running-scripting-migrations-from-code/).

Ho provato a replicare ciò che fa Add-Migration guardando attraverso il reflector .NET ma non riesco a trovare un modo di richiamare il comando System.Data.Entity.Migrations.AddMigrationCommand che viene chiamato tramite Powershell.

Qualcuno ha qualche idea su come posso avvicinarmi a realizzare questo senza fare qualcosa di estremamente disordinato? È qualcosa che penso che molte persone vorranno fare/hanno fatto ...

Molte grazie in anticipo!

+0

Vuoi che questo strumento crei effettivamente file di migrazione e li aggiunga al progetto? O semplicemente aggiorna il database a quale è il tuo schema di codice corrente? Se è il secondo, perché le migrazioni automatiche non sono un'opzione? Se è il primo, non puoi semplicemente aggiungere un evento build che esegue il comando 'Aggiungi-Migrazione'? – Rob

+0

@Rob Stiamo provando a creare uno strumento in base al quale il nostro CI può consumarlo e generare le nostre migrazioni per noi sul retro di un commit. Questo ci consentirà di creare automaticamente un MSI dal commit in modo che il modello rimanga sincronizzato con le migrazioni e il MSI non verrà interrotto. A causa delle dimensioni del nostro database, le migrazioni automatiche porteranno quasi certamente alla perdita automatica dei dati. 'Add-Migration' non sembra essere accessibile dall'esterno della shell VS – LukeHennerley

+0

Potresti chiarire che" le migrazioni automatiche porteranno quasi certamente alla perdita di dati automatica ". Perché pensi che ci sia qualche differenza tra * il tuo script * in esecuzione Add-Migration e EF in esecuzione Add-Migration? O è solo che vuoi eseguire a volte le migrazioni manuali e vuoi evitare di mescolare auto/manuale? –

risposta

8

Prima di tutto, non è possibile eseguire Nuget PowerShell all'esterno dello studio visivo (utilizza DTE). Inoltre, tutto ciò che scrivi senza Visual Studio deve essere inserito manualmente in csproj (ma non è un compito difficile).

Solo per mostrare come funziona, vi mando una riga di codici. Per testarli, creare MyDll dll (un test di progetto con contesto ed entità) e quindi abilitare manualmente le migrazioni su MyDll con Enable-Migrations (solo per creare Configuration.cs).

Dopo di che è possibile utilizzare questo pezzo di codice per generare il codice sorgente

DbConnectionInfo connectionStringInfo = new DbConnectionInfo(
    "Server=.;Database=MigrationTest;User=sa;Password=dacambiare", "System.Data.SqlClient"); // We shoud retrieve this from App.config 

ToolingFacade toolingFacade = new ToolingFacade(
    "MyDll", // MigrationAssemblyName. In this case dll should be located in "C:\\Temp\\MigrationTest" dir 
    "MyDll", // ContextAssemblyName. Same as above 
    null, 
    "C:\\Temp\\MigrationTest", // Where the dlls are located 
    "C:\\Temp\\MigrationTest\\App.config", // Insert the right directory and change with Web.config if required 
    "C:\\Temp\\App_Data", 
    connectionStringInfo) 
{ 
    LogInfoDelegate = s => {Console.WriteLine(s);}, 
    LogWarningDelegate = s => { Console.WriteLine("WARNING: " + s); }, 
    LogVerboseDelegate = s => { Console.WriteLine("VERBOSE: " + s); } 
}; 


ScaffoldedMigration scaffoldedMigration = toolingFacade.Scaffold("MyMigName", "C#", "MyAppNameSpace", false); 

Console.WriteLine(scaffoldedMigration.DesignerCode); 
Console.WriteLine("=================="); 
Console.WriteLine(scaffoldedMigration.UserCode); 

// Don't forget the resource file that is in the scaffoldedMigration 

EDIT
ho dimenticato gli spazi dei nomi e non vengono utilizzati spesso così qui si sono

using System; 
using System.Data.Entity.Infrastructure; 
using System.Data.Entity.Migrations.Design; 
4

Non una vera risposta alla tua domanda, piuttosto una condivisione della mia esperienza: sarei molto attento con le migrazioni generate per te in questo modo. Molte volte quando creo le migrazioni (in VS) le rivedo. Controllo se le modifiche proposte sono quelle che voglio che siano e EF non sta cercando di fare qualcosa di stupido (come la ridenominazione di colonne/tabelle facendo cadere una tabella e crearne una nuova).

Inoltre a volte EF manca di alcune modifiche critiche: recentemente ho avuto problemi a generare migrazioni corrette quando ho modificato le lunghezze dei campi nvarchar. Ciò ha anche richiesto un'attenta revisione delle migrazioni.

E anche le migrazioni sono codice. Stiamo eseguendo revisioni paritarie delle migrazioni prima che possano andare in produzione. La creazione automatica delle migrazioni renderà queste modifiche meno visibili e potenzialmente potrebbe causare una perdita di dati nella produzione.

E se si hanno problemi con le migrazioni in ambiente di squadra, abbiamo risolto questo problema comunicando: ogni volta che uno sviluppatore verifica una nuova migrazione, le e-mail vengono inviate a tutti gli altri sviluppatori di questo progetto. Risolto tutti i nostri problemi.

Aggiornamento Appena avuto una discussione con un collega e un altro problema è venuto fuori - come faresti il ​​tuo sviluppo locale? Vuoi creare migrazioni sulla macchina di dev, assicurati che tutto funzioni? Quindi eliminare la migrazione e il check-in del codice? e poi il tuo CI ricreerà la tua migrazione? Penso che questo danneggerà le menti di Dev quando lavorerà con EF.

+0

Sì, sarà necessario impedire il controllo delle migrazioni dagli sviluppatori o ciò causerà problemi – GraemeMiller

+1

@trailmax I nostri sviluppatori (attualmente) funzionano con migrazioni automatiche, rilasciamo e ricreamo il database ogni volta che modifichiamo le modifiche nell'ambiente di sviluppo per prevenire i problemi che si verificano quando si lavora con migrazioni basate su codice, all'interno di una squadra e all'interno del controllo del codice sorgente. Ma lei ha sollevato alcuni punti interessanti a cui non ho pensato, siamo nell'infanzia della nostra versione live utilizzando EF e migrazioni basate su codice e se avessimo di nuovo il nostro tempo, probabilmente non avremmo percorso la rotta EF . Fuori interesse come gestite le migrazioni basate su codice all'interno del vostro team? – LukeHennerley

+0

@LukeHennerley Le migrazioni automatiche non hanno mai funzionato per noi: troppo voodoo. Il nostro team apporta modifiche al modello code-first, emette il comando 'add-migration', ottiene lo stacked della migrazione - controlla se è una migrazione corretta. Lo applica al database di sviluppo locale, assicura che tutto funzioni come previsto. Ed è raro che la migrazione degli scaffold sia corretta sin dalla prima volta. Quindi esegue i test di integrazione che re-impalcatura il DB da zero. E quando tutto va bene, questo è il check-in, seguito dallo sviluppatore che invia un'email al team sulla nuova migrazione. – trailmax

1

È possibile utilizzare la classe System.Data.Entity.Migrations.Design.MigrationScaffolder per generare a livello di codice migrazioni in questo modo:

[TestMethod] 
public void GenerateTestMigration() 
{ 
    var config = new MyDbMigrationsConfiguration(); 
    var scaffolder = new MigrationScaffolder(config); 
    var pendingMigration = scaffolder.Scaffold("TestMigration"); 
    Trace.WriteLine(pendingMigration.UserCode); 
} 

Io uso questa e di altre tecniche sul nostro server di build di fallire la compilazione se ci sono le migrazioni in sospeso o se una migrazione deve essere creato in questo modo:

using Microsoft.VisualStudio.TestTools.UnitTesting; 
using System.Data.Entity.Migrations; 
using System.Data.Entity.Migrations.Design; 
using System.Diagnostics; 
using System.Linq; 

namespace YabbaDabbaDoo 
{ 
    [TestClass] 
    public class MigrationTests 
    { 
     [TestMethod] 
     [TestCategory("RunOnBuild")] 
     public void VerifyThereAreNoPendingMigrations() 
     { 
      // Arrange 
      var config = new MyDbMigrationsConfiguration(); 
      var dbMigrator = new DbMigrator(config); 

      // Act 
      var pendingMigrations = dbMigrator.GetPendingMigrations().ToList(); 

      // Visual Assertion 
      Trace.WriteLine(pendingMigrations); 

      // Assert 
      Assert.AreEqual(0, pendingMigrations.Count(), "There are pending EF migrations that need to be ran."); 
     } 

     [TestMethod] 
     [TestCategory("RunOnBuild")] 
     public void VerifyDatabaseIsCompatibleWithModel() 
     { 
      // Arrange 
      var context = new MyDbContext(); 

      // Act 
      var isCompatible = context.Database.CompatibleWithModel(false); 

      // Visual Assertion 
      if (!isCompatible) 
      { 
       var config = new MyDbMigrationsConfiguration(); 
       var scaffolder = new MigrationScaffolder(config); 
       var pendingMigration = scaffolder.Scaffold("MissingMigration"); 

       Trace.WriteLine("Missing Migration:"); 
       Trace.WriteLine(""); 
       Trace.WriteLine(pendingMigration.UserCode); 
      } 

      // Assert 
      Assert.IsTrue(isCompatible, "The EF model is not compatible with the database. An EF migration needs to be created. See output for sample of missing migration."); 
     } 
    } 
} 
Problemi correlati