EF 6重命名SQL Server时态表列触发SqlException事务不匹配
解决EF6迁移SQL Server时态表列重命名的事务计数不匹配问题
问题根源
SQL Server时态表开启系统版本控制后,会自动维护历史表的同步操作。EF6自动生成的迁移脚本直接调用sp_rename重命名列时,会干扰SQL Server内部的事务逻辑,导致事务计数不匹配,触发Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements错误。
可行解决方案
方案1:手动修改生成的迁移脚本
直接编辑EF生成的SQL脚本,补充时态表专属处理逻辑:
BEGIN TRANSACTION; -- 1. 禁用目标表的系统版本控制 ALTER TABLE [dbo].[YourEntityTable] SET (SYSTEM_VERSIONING = OFF); -- 2. 重命名当前表的目标列 EXEC sp_rename '[dbo].[YourEntityTable].[OldColumn]', 'NewColumn', 'COLUMN'; -- 3. 同步重命名历史表的对应列(必须执行,否则无法重新启用版本控制) EXEC sp_rename '[dbo].[YourEntityTableHistory].[OldColumn]', 'NewColumn', 'COLUMN'; -- 4. 重新启用系统版本控制,关联原历史表 ALTER TABLE [dbo].[YourEntityTable] SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[YourEntityTableHistory])); COMMIT TRANSACTION;
方案2:在EF迁移类中编写自定义逻辑
替代EF自动生成的RenameColumn调用,在迁移类的Up和Down方法中手动编写完整的SQL操作:
public partial class RenameEntityColumn : DbMigration { public override void Up() { // 禁用系统版本控制 Sql(@"ALTER TABLE [dbo].[YourEntityTable] SET (SYSTEM_VERSIONING = OFF);"); // 重命名列 Sql(@"EXEC sp_rename '[dbo].[YourEntityTable].[OldColumn]', 'NewColumn', 'COLUMN';"); Sql(@"EXEC sp_rename '[dbo].[YourEntityTableHistory].[OldColumn]', 'NewColumn', 'COLUMN';"); // 重新启用系统版本控制 Sql(@"ALTER TABLE [dbo].[YourEntityTable] SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[YourEntityTableHistory]));"); } public override void Down() { // 反向回滚操作 Sql(@"ALTER TABLE [dbo].[YourEntityTable] SET (SYSTEM_VERSIONING = OFF);"); Sql(@"EXEC sp_rename '[dbo].[YourEntityTable].[NewColumn]', 'OldColumn', 'COLUMN';"); Sql(@"EXEC sp_rename '[dbo].[YourEntityTableHistory].[NewColumn]', 'OldColumn', 'COLUMN';"); Sql(@"ALTER TABLE [dbo].[YourEntityTable] SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[YourEntityTableHistory]));"); } }
关键注意事项
- 必须同步重命名当前表和历史表的列,否则重新启用系统版本控制会失败
- 执行操作前确保目标表无其他正在运行的事务,避免锁表
- 生产环境操作前建议备份历史表数据
内容的提问来源于stack exchange,提问作者Marcel Alfonso
相关产品推荐
相关产品推荐

