Migraciones de EF5 - Error de variable duplicada / redefinida al eliminar restricciones | Problema con el uso del comando SQL GO

Fondo:

Tenemos un proyecto que utiliza.ef-migraciones que contiene múltiples (lea ~ 60) migraciones creadas durante un largo período de desarrollo. Naturalmente, algunas de estas migraciones también involucran:

eliminando restricciones1,2creando disparadores

Todo es unicornios y arco iris cuando corremos.

Update-Database

porque cada migración se ejecuta como un lote separado. Pero al crearSQL Scripts para estas migraciones usando

Update-Database -Script

encontramos algunos problemas como se describe a continuación:

Problema 1:

Cuando se eliminan varias restricciones en varios archivos de migración, el script generado por EF tiende a volver a declarar las variables que utiliza para eliminar. Esto se debe a que garantiza la exclusividad de los nombres de las variables dentro del mismo archivo de migración, pero al cambiar el archivo, restablece el contador, superponiendo así los nombres.

Problema 2:

SQL impone queCREATE TRIGGER Siempre es la primera declaración en un lote. Cuando se genera el script, EF es ajeno a los contenidos deSql("CREATE TRIGGER ... "); Y por lo tanto no lo trata especialmente. Por lo tanto, la declaración puede aparecer justo en el medio de un archivo de script, y se produce un error.

Solución: (o eso creíamos!)

Una solución común / de sentido común para los dos problemas es insertar Begin / End the sql batch en los lugares correctos. Hacer esto manualmente me haría un hombre muy rico, por lo que no es una solución eficiente.

En su lugar, utilizamos eltécnica proporcionada por @DavidSette. Creando un nuevoBatchSqlServerMigrationSqlGenerator heredando deSqlServerMigrationSqlGenerator que anula efectivamentedropColumnOperation ysqlOperation y luego forzando unGO Declaración sobre los sensibles como tales:

protected override void Generate (System.Data.Entity.Migrations.Model.DropColumnOperation dropColumnOperation)
{
    base.Generate(dropColumnOperation);
    Statement("GO");
}
Boo Boo:

Esta solución deja de funcionarUpdate-Database sin el-Script bandera con el siguiente error:

System.Data.SqlClient.SqlException (0x80131904): Could not find stored procedure 'GO'.

Lo cual fue agregado por nuestro generador personalizado. Ahora no estoy seguro de por qué, pero debería haber una buena razón para que EF no lo reconozcaGO!

Más información:

Migraciones: duplicar @ var0 variables en el script que elimina dos restriccionesEl nombre de la variable '@number' ya ha sido declarado¿Cómo puedo anular los scripts SQL generados por MigratorScriptingDecorator?Migraciones de Entity Framework: incluye la instrucción Go solo en la salida de código

Error 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'.

Así que básicamente arreglar los scripts rompe un comando esencial. ¡Por favor, ayúdame a decidir cuál es el menor de los dos males!

Respuestas a la pregunta(4)

Su respuesta a la pregunta