2013-06-14 3 views
10

Итак, у меня есть приложение с тоннами миграций, созданных инфраструктурой Entity. Мы хотим получить скрипт для всех миграций сразу, и с помощью тега -Script все работает нормально.Добавление операторов «GO» для миграции Entity Framework

... Однако это не добавляет GO заявления в SQL дает нам проблемы, как Alter view should be the first statement in a batch file...

Я искал вокруг и вручную добавлять Sql("GO"); помощи с этой проблемой, но только для всего сценария. Когда я снова использую диспетчер консоли пакета, он возвращает исключение.

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

Есть ли способ, чтобы добавить эти GO тегов только при использовании -Script тега? Если нет, то для чего это хороший подход?

Примечание: мы также пытались иметь несколько файлов, но поскольку у нас так много миграций, это почти невозможно поддерживать каждый раз.

ответ

10

Для того, чтобы изменить SQL, сгенерированный с помощью каркасной организации миграции вы можете создать новый SqlServerMigrationSqlGenerator

Мы сделали это, чтобы добавить GO заявления до и после истории миграции:

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

     base.Generate(insertHistoryOperation); 

     Statement("GO"); 

    } 
} 

затем добавить в Configuration конструктора (в Migrations папке проекта, где вы DbContext есть), так что он использует этот новый генератор SQL:

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

Так что теперь при создании сценария с помощью тега -script, вы можете увидеть, что insert into [__MigrationHistory] окружен GO

В качестве альтернативы в вашей реализации SqlServerMigrationSqlGenerator вы можете переопределить любую часть генерации скрипта, то InsertHistoryOperation подходит для нас.

+2

Прекрасно работает при использовании тега '-Script'. Я должен прокомментировать «SetSqlGenerator (« ..... », однако, когда я его не использую, потому что в противном случае я снова получил исключение. Это, однако, экономит мне массу времени, потому что это просто комментирование строки вместо добавление 'Sql (« GO »);' везде. Спасибо! – Tikkes

+0

Я не могу найти InsertHistoryOperation.В какой сборке он находится? –

+3

А я думаю, что он переименован в EF 6 в HistoryOperation –

13

Если вы пытаетесь изменить свое мнение, используя Sql('Alter View dbo.Foos As etc'), то вы можете избежать ошибок should be the first statement in a batch file без добавления GO заявления, поставив SQL внутри EXEC команды:

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

+0

Эта вещь позволяет заполнить таблицы и столбцы сразу после создания. Большой! – blazkovicz

+0

WOW, это действительно просто и работает! Спасибо за это! – trailmax

+0

Лучшие поклонники, спасибо! – ArDumez

-2

Просто замените текущее заявление с a .Replace («GO», «»);

8

Оставьте концепцию в глубине SqlServerMigrationSqlGenerator как необязательный аргумент для Statement(sql, batchTerminator). Вот что-то, основанное на идее Skyp. Он работает как в режиме ввода, так и без него. GO для разных операций, чем для Skyp, только потому, что наши потребности немного отличаются. Затем вам необходимо зарегистрировать этот класс в Configuration согласно инструкциям 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

Это сработало для меня! Я искал способ, который работает как с аргументом -script, так и без него. Благодаря! – ravinsp

+0

Это работало для меня, когда EF6 необъяснимо удалял инструкцию go из конца моего скрипта создания хранимой процедуры, вставленного через SqlResource. Магия EF - это не то, что я люблю. – aaaaaa

Смежные вопросы