Migrações EF5 - Bug de variável duplicado / redefinido ao eliminar restrições | Problema com o uso do comando SQL GO
Nós temos um projeto que usaef-migrações contendo migrações múltiplas (leitura ~ 60) criadas durante um longo período de desenvolvimento. Naturalmente, algumas dessas migrações também envolvem:
soltando restrições1,2criando gatilhosTudo é unicórnios e arco-íris quando corremos
Update-Database
porque cada migração é executada como um lote separado. Mas ao criarSQL Scripts
para essas migrações usando
Update-Database -Script
Encontramos alguns problemas, conforme descrito abaixo:
Problema 1:Ao eliminar várias restrições em vários arquivos de migração, o script gerado pelo EF tende a declarar novamente as variáveis que ele usa para descartar. Isso ocorre porque garante a exclusividade dos nomes das variáveis dentro do mesmo arquivo de migração, mas na alteração do arquivo, ele redefine o contador, sobrepondo, assim, os nomes.
Problema 2:SQL impõe queCREATE TRIGGER
é sempre a primeira instrução em um lote. Quando o script é gerado, EF fica alheio ao conteúdo deSql("CREATE TRIGGER ... ");
e, portanto, não trata nada de especial. Assim, a declaração pode aparecer no meio de um arquivo de script e com erro.
Uma solução comum / de senso comum para os dois problemas é inserir Begin / End the sql batch nos lugares certos. Fazer isso manualmente me tornaria um homem muito rico, então essa não é uma solução eficiente.
Em vez disso, usamos otécnica fornecida por @DavidSette. Criando um novoBatchSqlServerMigrationSqlGenerator
herdando deSqlServerMigrationSqlGenerator
que efetivamente substituidropColumnOperation
esqlOperation
e depois forçando umGO
declaração em torno dos sensíveis como tal:
protected override void Generate (System.Data.Entity.Migrations.Model.DropColumnOperation dropColumnOperation)
{
base.Generate(dropColumnOperation);
Statement("GO");
}
Boo Boo:Esta solução quebra correndoUpdate-Database
sem o-Script
sinalizador com o seguinte erro:
System.Data.SqlClient.SqlException (0x80131904): Could not find stored procedure 'GO'.
Que foi adicionado pelo nosso gerador personalizado. Agora eu não tenho certeza do porquê, mas deve haver uma boa razão para a EF não reconhecerGO
!
Mais informações:
Migrações: Variáveis duplicadas @ var0 no script que solta duas restriçõesO nome da variável '@number' já foi declaradoComo posso substituir scripts SQL gerados pelo MigratorScriptingDecoratorMigrações de estrutura de entidades: Incluindo a instrução Go somente na saída de -ScriptErro completo:
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'.
Então, basicamente, consertar os scripts quebra um comando essencial. Por favor me ajude a decidir qual é o menor dos dois males!