История:
У нас есть проект, который использует ef-migrations содержащий несколько (прочитанных ~ 60) миграций, созданных в течение длительного периода разработки. Естественно, некоторые из этих миграций также включают:
Все единороги и радуги, когда мы запускаем
Update-Database
потому что каждая миграция выполняется как отдельная партия. Но при создании SQL Scripts
для этих миграций с использованием
Update-Database -Script
мы столкнулись с несколькими проблемами, описанными ниже:
Проблема 1:
При отбрасывании нескольких ограничений для нескольких файлов миграции script, сгенерированный EF, имеет тенденцию повторно объявлять переменные, которые он использует для удаления. Это связано с тем, что он обеспечивает уникальность имен переменных в одном файле миграции, но при изменении файла он сбрасывает счетчик, тем самым перекрывая имена.
Проблема 2:
SQL устанавливает, что CREATE TRIGGER
всегда является первым оператором в пакете. Когда генерируется script, EF не обращает внимания на содержимое Sql("CREATE TRIGGER ... ");
и поэтому не относится к нему специально. Таким образом, оператор может отображаться прямо в середине файла script и ошибки.
Решение: (или так мы думали!)
Общим/здравым смыслом решения двух проблем является вставка Begin/End пакет sql в нужном месте. Вручную это сделало бы меня очень богатым человеком, так что это не эффективное решение.
Вместо этого мы использовали технику предоставленную @DavidSette. Создание нового BatchSqlServerMigrationSqlGenerator
, наследующего от SqlServerMigrationSqlGenerator
, который эффективно переопределяет dropColumnOperation
и sqlOperation
, а затем заставляет оператор GO
вокруг чувствительных как таковых:
protected override void Generate (System.Data.Entity.Migrations.Model.DropColumnOperation dropColumnOperation)
{
base.Generate(dropColumnOperation);
Statement("GO");
}
Boo Boo:
Это решение прерывает запуск Update-Database
без флага -Script
со следующей ошибкой:
System.Data.SqlClient.SqlException (0x80131904): Could not find stored procedure 'GO'.
Что было добавлено нашим настраиваемым генератором. Теперь я не уверен, почему, но должна быть хорошая причина, по которой EF не распознает GO
!
Дополнительная информация:
- Миграции: Дублировать переменные @var0 в script, которые упускают два ограничения
- Имя переменной "@number" уже объявлено
- Как я могу переопределить SQL-скрипты, сгенерированные MigratorScriptingDecorator.
- Миграции Entity Framework: включение оператора Go только в - Script вывод
Полная ошибка:
Applying code-based migration: 201205181406363_AddTriggerForOverlap.
GO
System.Data.SqlClient.SqlException (0x80131904): Could not find stored procedure 'GO'.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at System.Data.Entity.Migrations.DbMigrator.ExecuteSql(DbTransaction transaction, MigrationStatement migrationStatement)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ExecuteSql(DbTransaction transaction, MigrationStatement migrationStatement)
at System.Data.Entity.Migrations.DbMigrator.ExecuteStatements(IEnumerable`1 migrationStatements)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.ExecuteStatements(IEnumerable`1 migrationStatements)
at System.Data.Entity.Migrations.DbMigrator.ExecuteOperations(String migrationId, XDocument targetModel, IEnumerable`1 operations, Boolean downgrading, Boolean auto)
at System.Data.Entity.Migrations.DbMigrator.ApplyMigration(DbMigration migration, DbMigration lastMigration)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ApplyMigration(DbMigration migration, DbMigration lastMigration)
at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)
at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.RunCore()
at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run()
ClientConnectionId:ac53af4b-1f9b-4849-a0da-9eb33b836caf
Could not find stored procedure 'GO'.
Таким образом, в основном исправление скриптов нарушает важную команду. Пожалуйста, помогите мне решить, что является меньшим из двух зол!