2013-06-14 30 views
10

Così ho un'applicazione con un sacco di migrazioni effettuate da Entity framework. Vogliamo ottenere uno script per tutte le migrazioni contemporaneamente e utilizzare il tag -Script funziona correttamente.Aggiunta di istruzioni "GO" alle migrazioni di Entity Framework

Tuttavia ... non aggiunge GO dichiarazioni in SQL dandoci problemi come Alter view should be the first statement in a batch file...

Ho cercato in giro e aggiungere manualmente Sql("GO"); aiuto con questo problema, ma solo per l'intero script. Quando uso di nuovo il gestore della console del pacchetto, restituisce un'eccezione.

System.Data.SqlClient.SqlException (0x80131904): Could not find stored procedure 'GO'. 

Esiste un modo per aggiungere questi tag GOsolo quando si utilizza il tag -Script? In caso contrario, quale è un buon approccio per questo?

Nota: abbiamo anche provato ad avere più file, ma dal momento che abbiamo così tante migrazioni, questo è quasi impossibile da mantenere ogni volta.

risposta

10

Al fine di modificare il codice SQL generato dalle migrazioni Entity Framework è possibile creare un nuovo SqlServerMigrationSqlGenerator

Lo abbiamo fatto per aggiungere una dichiarazione GO prima e dopo la storia di migrazione:

public class MigrationScriptBuilder: SqlServerMigrationSqlGenerator 
{ 
    protected override void Generate(System.Data.Entity.Migrations.Model.InsertHistoryOperation insertHistoryOperation) 
    { 
     Statement("GO"); 

     base.Generate(insertHistoryOperation); 

     Statement("GO"); 

    } 
} 

quindi aggiungere nel Configuration costruttore (nella cartella Migrations del progetto in cui si è DbContext) in modo che utilizza questo nuovo generatore di sql:

[...] 
internal sealed class Configuration : DbMigrationsConfiguration<PMA.Dal.PmaContext> 
{ 
    public Configuration() 
    { 
     SetSqlGenerator("System.Data.SqlClient", new MigrationScriptBuilder()); 
     AutomaticMigrationsEnabled = false; 
    } 
[...] 

Così ora quando si genera uno script utilizzando il tag -Script, si può vedere che la insert into [__MigrationHistory] è circondato da GO

alternativa nell'implementazione di SqlServerMigrationSqlGenerator è possibile sostituire qualsiasi parte della generazione dello script, il InsertHistoryOperation era adatto per noi.

+2

Funziona perfettamente quando si utilizza il tag '-Script'. Devo commentare "SetSqlGenerator (" ..... 'linea tuttavia quando non lo uso perché altrimenti ho ottenuto di nuovo l'eccezione. Ciò tuttavia mi risparmia un sacco di tempo perché è solo commentare una riga invece di aggiungendo 'Sql (" GO ");' ovunque. Grazie! – Tikkes

+0

Non riesco a trovare InsertHistoryOperation.In quale assemblaggio è? –

+3

Ah Penso che sia rinominato in EF 6 a HistoryOperation –

13

Se si sta tentando di modificare la vostra vista utilizzando Sql('Alter View dbo.Foos As etc'), allora si può evitare l'errore should be the first statement in a batch file senza aggiungere GO dichiarazioni mettendo lo SQL all'interno di un comando EXEC:

Sql(EXEC('Alter View dbo.Foos As etc'))

+0

Questa cosa permette di riempire tabelle e colonne subito dopo la creazione. Grande! – blazkovicz

+0

WOW, è davvero semplice e funziona! grazie per quello! – trailmax

+0

I migliori anwers, grazie !! – ArDumez

-2

Basta sostituire l'espressione corrente con a .Replace ("GO", "");

8

Il concetto esiste in profondità nello SqlServerMigrationSqlGenerator come argomento facoltativo per Statement(sql, batchTerminator). Ecco qualcosa basato sull'idea di Skyp. Funziona sia in modalità script che no. I GO sono per operazioni diverse rispetto a Skyp solo perché le nostre esigenze sono leggermente diverse. È quindi necessario registrare questa classe nel Configuration come da istruzioni di Skyp.

public class MigrationScriptBuilder : SqlServerMigrationSqlGenerator 
    { 
     private string Marker = Guid.NewGuid().ToString(); //To cheat on the check null or empty of the base generator 

     protected override void Generate(AlterProcedureOperation alterProcedureOperation) 
     { 
      SqlGo(); 
      base.Generate(alterProcedureOperation); 
      SqlGo(); 
     } 
     protected override void Generate(CreateProcedureOperation createProcedureOperation) 
     { 
      SqlGo(); 
      base.Generate(createProcedureOperation); 
      SqlGo(); 
     } 
     protected override void Generate(SqlOperation sqlOperation) 
     { 
      SqlGo(); 
      base.Generate(sqlOperation); 
     } 

     private void SqlGo() 
     { 
      Statement(Marker, batchTerminator: "GO"); 
     } 

     public override IEnumerable<MigrationStatement> Generate(IEnumerable<MigrationOperation> migrationOperations, string providerManifestToken) 
     { 
      var result = new List<MigrationStatement>(); 
      var statements = base.Generate(migrationOperations, providerManifestToken); 

      bool pendingBatchTerminator = false; 
      foreach (var item in statements) 
      { 
       if(item.Sql == Marker && item.BatchTerminator == "GO") 
       { 
        pendingBatchTerminator = true; 
       } 
       else 
       { 
        if(pendingBatchTerminator) 
        { 
         item.BatchTerminator = "GO"; 
         pendingBatchTerminator = false; 
        } 
        result.Add(item); 
       } 
      } 

      return result; 
     } 
    } 
+1

Questo ha funzionato per me! Stavo cercando un modo che funzioni sia con che senza argomenti script. Grazie! – ravinsp

+0

Questo ha funzionato per me quando EF6 rimuoveva inspiegabilmente un'istruzione go dalla fine del mio script di creazione della stored procedure che veniva inserito tramite SqlResource. La magia di EF non è qualcosa a cui sono affezionato. – aaaaaa

Problemi correlati