Добавление операторов GO в миграции Entity Framework
Итак, у меня есть приложение с множеством миграций, сделанных платформой Entity. Мы хотим получить скрипт для всех миграций одновременно и использовать -Script
тег работает нормально.
Однако... это не добавляет 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
тег? Если нет, то какой подход к этому хорош?
Примечание: мы также пытались иметь несколько файлов, но поскольку у нас так много миграций, практически невозможно поддерживать их каждый раз.
4 ответа
Чтобы изменить 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
был подходит для нас.
Если вы пытаетесь изменить свое мнение с помощью 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'))
Оказывается, концепция существует глубоко в SqlServerMigrationSqlGenerator
в качестве необязательного аргумента для Statement(sql, batchTerminator)
, Вот кое-что, основанное на идее Скайпа. Работает как в режиме -script, так и нет. GO предназначены для операций, отличных от Skyp, только потому, что наши потребности немного отличаются. Затем вам нужно зарегистрировать этот класс в Configuration
согласно инструкциям Скайпа.
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;
}
}