EF5迁移 - 删除约束时重复/重新定义的变量错误|使用SQL GO命令的问题

时间:2012-11-27 17:42:23

标签: entity-framework tsql entity-framework-5 ef-migrations

背景:

我们有一个使用的项目,其中包含在长时间开发期间创建的多个(读取~60个)迁移。当然,其中一些迁移也涉及:

  • 删除约束 12
  • 创建触发器

当我们跑步时,一切都是独角兽和彩虹

Update-Database

因为每次迁移都是作为单独的批处理运行的。但是在使用

为这些迁移创建SQL Scripts
Update-Database -Script

我们遇到了一些问题,如下所述:

问题1:

在多个迁移文件中删除多个约束时,EF生成的脚本会重新声明它用于删除的变量。这是因为它确保了同一个迁移文件中变量名的唯一性,但是在更改文件时,它会重置计数器,从而重叠名称。

问题2:

SQL强制CREATE TRIGGER始终是批处理中的第一个语句。生成脚本时,EF无视Sql("CREATE TRIGGER ... ");的内容,因此不会特别对待它。因此,该语句可能出现在脚本文件的中间,并且出错。

解决方案:(或者我们想到了!)

这两个问题的常见/常识解决方案是在正确的位置插入开始/结束sql批处理。手动这样做会让我成为一个非常富有的人,所以这不是一个有效的解决方案。

相反,我们使用technique provided by @DavidSette。创建一个新的BatchSqlServerMigrationSqlGenerator继承自SqlServerMigrationSqlGenerator,有效地覆盖dropColumnOperationsqlOperation,然后强制围绕敏感的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

更多信息:

  1. Migrations: Duplicate @var0 variables in script that drops two constraints
  2. The variable name '@number' has already been declared
  3. How can I override SQL scripts generated by MigratorScriptingDecorator
  4. Entity Framework Migrations: Including Go statement only in -Script output
  5. 完整错误:

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

    所以基本上修复脚本会打破一个基本命令。请帮我决定两个邪恶中哪一个更小!

4 个答案:

答案 0 :(得分:2)

我放了一个Sql(" - < GO>");在每次迁移结束时。这可以作为应用的迁移运行,当我编写SQL脚本时,我只需在" - < GO>"上执行查找和替换。到" GO"。有点手册但对我有用。你可以把Sql(" - < GO>");围绕你的创建触发器语句。

答案 1 :(得分:1)

根据msdn

“GO不是Transact-SQL语句;它是由sqlcmd和osql实用程序以及SQL Server Management Studio代码编辑器识别的命令。”

由于你没有使用上述任何工具,而是使用SqlCommand类来执行你的Sql语句Sql Server(而不是EF - 看看发生异常的堆栈跟踪)是否会窒息

答案 2 :(得分:1)

在我经历了problem first hand ..

之后

我们决定创建较小的迁移。如果更改足够大以至于需要GO命令,那么开发人员试图在迁移中进行过多更改。不幸的是,控制迁移内容的唯一方法就是注释掉更改。

我也在思考为什么我要这么糟糕的剧本。它不像我不相信EF正确执行迁移(假设我先测试它)。理想情况下,我永远不会(谢天谢地)有理由修改它。当我开始使用EF Code First时,我只看过几次。

我不喜欢这个答案,但我认为除了调试Entity Framework Code First的迁移之外,它不会起作用。

答案 3 :(得分:-1)

只需删除此行的所有重复:

DECLARE @var0 nvarchar(128)

只有第一个声明就足够了。您的脚本将顺利运行! :)