2013-06-14 4 views
10

Mam więc aplikację z mnóstwem migracji wykonanych przez framework Entity. Chcemy uzyskać skrypt dla wszystkich migracji naraz i użycie tagu -Script nie działa poprawnie.Dodawanie instrukcji "GO" do migracji Entity Framework

... jednak nie dodać GO oświadczeń w SQL dając nam problemów jak Alter view should be the first statement in a batch file...

I zostały poszukiwania wokół i ręczne dodawanie Sql("GO"); pomóc z tym problemem, ale tylko dla całego skryptu. Kiedy ponownie używam menedżera konsoli pakietów, zwraca on wyjątek.

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

Czy istnieje sposób dodać te GO tagów tylko przy użyciu znacznika -Script? Jeśli nie, jakie jest dobre podejście do tego?

Uwaga: próbowaliśmy również wielu plików, ale ponieważ mamy tak wiele migracji, jest prawie niemożliwe do utrzymania za każdym razem.

Odpowiedz

10

W celu zmiany SQL generowane przez migracje Entity Framework można utworzyć nowy SqlServerMigrationSqlGenerator

Zrobiliśmy to, aby dodać oświadczenie GO przed i po historii migracji:

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

     base.Generate(insertHistoryOperation); 

     Statement("GO"); 

    } 
} 

następnie dodać w konstruktorze Configuration (w folderze Migrations projektu gdzie DbContext jest), tak, że wykorzystuje ten nowy generator sql:

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

Więc teraz podczas generowania skryptu przy użyciu znacznika -script, można zobaczyć, że insert into [__MigrationHistory] otoczony GO

Alternatywnie w realizacji SqlServerMigrationSqlGenerator można zastąpić dowolną część pokolenia skrypcie InsertHistoryOperation była odpowiednia dla nas.

+2

Działa doskonale podczas używania znacznika '-Script'. Muszę skomentować linię 'SetSqlGenerator (" ..... ', jednak gdy jej nie używam, ponieważ w przeciwnym razie uzyskałem wyjątek ponownie, co jednak oszczędza mi mnóstwo czasu, ponieważ jest to po prostu komentowanie zamiast linii zamiast dodawanie 'Sql (" GO ");' wszędzie. Dzięki! – Tikkes

+0

Nie mogę znaleźć InsertHistoryOperation.Który to zestaw? –

+3

Ah Myślę, że zmieniono nazwę w EF 6 na HistoryOperation –

13

Jeśli chcesz zmienić swój pogląd korzystając Sql('Alter View dbo.Foos As etc'), wtedy można uniknąć błędu should be the first statement in a batch file bez dodawania GO oświadczenia poprzez umieszczenie SQL wewnątrz EXEC polecenia:

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

+0

Dzięki temu możemy wypełniać tabele i kolumny zaraz po utworzeniu. Wspaniały! – blazkovicz

+0

WOW, to naprawdę proste i działa! Dziękuję za to! – trailmax

+0

Najlepszych anwerów, dzięki! – ArDumez

-2

Wystarczy zastąpić aktualne oświadczenie o a. Przepis ("GO", "");

8

Wyłączyć koncepcję istnieje głęboko w SqlServerMigrationSqlGenerator jako opcjonalny argument dla Statement(sql, batchTerminator). Oto coś na podstawie pomysłu Skypa. Działa zarówno w trybie -script, jak i nie. GO są przeznaczone do różnych operacji niż dla Skyp tylko dlatego, że nasze potrzeby są nieco inne. Następnie musisz zarejestrować tę klasę w Configuration zgodnie z instrukcjami 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

To zadziałało dla mnie! Szukałem sposobu, który działa zarówno z argumentem -script, jak i bez niego. Dzięki! – ravinsp

+0

To działało dla mnie, gdy EF6 w niewytłumaczalny sposób usuwał instrukcję "go" od momentu zakończenia wstawiania skryptu tworzenia procedury składowanej przez SqlResource. Magia EF nie jest czymś, co lubię. – aaaaaa