Добавление операторов 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;
        }
    }

Самый простой способ - добавить /**/ перед оператором GO.

Просто замените текущий оператор на.Replace("GO", "");

Другие вопросы по тегам