EF Core迁移脚本:编写列存在时执行的幂等INSERT语句
解决EF Core迁移脚本中幂等性INSERT的列存在性问题
这个问题的核心在于SQL Server会在执行整个批处理前解析所有语句——哪怕你的INSERT被IF NOT EXISTS包裹,第二次执行时SQL引擎还是会先检查OldB列是否存在,导致报错,哪怕这个INSERT根本不会被执行。
要解决这个问题,你需要把INSERT逻辑放到动态SQL中,因为动态SQL是在运行时才会被解析执行的,只有当外层的IF条件满足时(也就是迁移还没执行过,此时OldB列肯定存在),才会解析并执行里面的INSERT语句。
修改后的脚本如下:
IF NOT EXISTS (SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'AName') BEGIN -- 用动态SQL延迟解析INSERT语句,避免列不存在时的解析错误 EXEC(N'INSERT INTO Foos (A, B) SELECT OldA, OldB FROM Bars'); -- 手动插入迁移记录(确保EF Core的迁移状态跟踪正确) INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'AName', '你的EF Core版本号'); END -- 后续的DROP COLUMN脚本保持不变 IF NOT EXISTS (SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'AnotherName') BEGIN ALTER TABLE [Bars] DROP COLUMN [OldB]; INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'AnotherName', '你的EF Core版本号'); END
额外优化:增加列存在性检查(可选)
如果你想让脚本更健壮,可以在IF条件里额外检查OldB列是否存在,确保万无一失:
IF NOT EXISTS (SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'AName') AND EXISTS (SELECT 1 FROM sys.columns WHERE Name = N'OldB' AND Object_ID = OBJECT_ID(N'Bars')) BEGIN EXEC(N'INSERT INTO Foos (A, B) SELECT OldA, OldB FROM Bars'); INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'AName', '你的EF Core版本号'); END
这样一来,第二次执行脚本时,外层IF条件不满足,动态SQL不会被解析执行,也就不会触发OldB列不存在的错误,完美实现幂等性。
内容的提问来源于stack exchange,提问作者Tomas Aschan
相关产品推荐
相关产品推荐

