17

背景:

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

  • 删除约束1 , 2
  • 创建触发器

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

Update-Database

因为每个迁移都作为单独的批次运行。但是在SQL Scripts为这些迁移创建时使用

Update-Database -Script

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

问题1:

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

问题2:

SQL 强制它CREATE TRIGGER始终是批处理中的第一条语句。生成脚本时,EF 不知道其中的内容,Sql("CREATE TRIGGER ... ");因此不会对其进行任何特殊处理。因此,该语句可能会出现在脚本文件的中间,并且会出错。

解决方案:(或者我们认为!)

这两个问题的常见/常识性解决方案是在正确的位置插入 Begin/End sql 批处理。手动执行此操作会使我成为一个非常富有的人,因此这不是一个有效的解决方案。

相反,我们使用了@DavidSette 提供的技术。创建一个新的BatchSqlServerMigrationSqlGenerator继承SqlServerMigrationSqlGenerator,有效地覆盖dropColumnOperationsqlOperation然后GO围绕敏感的强制声明:

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

嘘嘘:

Update-Database此解决方案在没有标志的情况下中断运行,-Script并出现以下错误:

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

这是由我们的自定义生成器添加的。现在我不确定为什么,但应该有一个很好的理由 EF 无法识别GO

更多信息:

  1. 迁移:在删除两个约束的脚本中重复 @var0 变量
  2. 变量名称“@number”已被声明
  3. 如何覆盖 MigratorScriptingDecorator 生成的 SQL 脚本
  4. 实体框架迁移:仅在 -Script 输出中包含 Go 语句

完整错误:

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

4 回答 4

2

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

于 2013-03-12T16:59:32.640 回答
1

根据msdn

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

由于您没有使用上述任何工具,而是使用 SqlCommand 类来执行您的 Sql 语句 Sql Server(而不是 EF - 请参阅异常起源的堆栈跟踪)正在阻塞它

于 2012-11-27T18:52:59.837 回答
1

在我亲身经历了这个问题之后..

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

我也思考过为什么我那么想要这个剧本。这不像我不相信 EF 能够正确执行迁移(前提是我先对其进行了测试)。理想情况下,我永远不会也(谢天谢地)还没有理由修改它。当我开始使用 EF Code First 时,我只看过几次。

我不喜欢这个答案,但我认为它除了调试 Entity Framework Code First 的迁移之外没有其他目的。

于 2012-11-27T20:17:35.700 回答
-1

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

DECLARE @var0 nvarchar(128)

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

于 2013-11-11T04:29:42.580 回答