Добавление операторов "GO" в миграцию Entity Framework
Итак, у меня есть приложение с тонной миграцией, созданной инфраструктурой Entity.
Мы хотим получить script для всех перемещений сразу, и использование тега -Script
работает нормально.
Однако... он не добавляет в SQL инструкции GO
, дающие нам такие проблемы, как Alter view should be the first statement in a batch file...
Я искал и вручную добавлял Sql("GO");
справку с этой проблемой, но только для всего script. Когда я снова использую диспетчер консоли пакета, он возвращает исключение.
System.Data.SqlClient.SqlException (0x80131904): Could not find stored procedure 'GO'.
Есть ли способ добавить эти теги GO
только при использовании тега -Script
?
Если нет, то для этого хороший подход?
Примечание. Мы также пытались иметь несколько файлов, но поскольку у нас так много миграций, это почти невозможно поддерживать каждый раз.
Ответы
Ответ 1
Чтобы изменить миграцию SQL Generated by entity, вы можете создать новый 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 с помощью тега Script, вы можете видеть, что insert into [__MigrationHistory]
окружен GO
В качестве альтернативы в вашей реализации SqlServerMigrationSqlGenerator
вы можете переопределить любую часть генерации script, нам подходит InsertHistoryOperation
.
Ответ 2
Если вы пытаетесь изменить свое представление с помощью 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'))
Ответ 3
Выключите концепцию в глубину SqlServerMigrationSqlGenerator
как необязательный аргумент для Statement(sql, batchTerminator)
. Вот что-то, основанное на идее Skyp. Он работает как в режиме script, так и без него. 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;
}
}
Ответ 4
Просто замените текущую инструкцию на .Replace( "GO", "");