Sup*_*pez 7 sql-server entity-framework entity-framework-core azure-sql-database
我正在使用 EF Core (3.1.15)。在之前的迁移中(也是在 3.1.15 中创建的),引用了一个后来被删除的列。幂等脚本会检查是否在数据库上执行了迁移(确实如此,并且引用仍然显示在表中__EFMigrationsHistory)。但是,由于列不存在,检查没有预期的结果和脚本。
问:为什么不存在的列会导致 SQL 脚本的执行失败?
脚本是用创建的
dotnet-ef migrations script -i -o migrations.sql
Run Code Online (Sandbox Code Playgroud)
失败的自动化脚本的相关部分,ReferenceToLedgerId在以后的迁移中删除的列在哪里:
dotnet-ef migrations script -i -o migrations.sql
Run Code Online (Sandbox Code Playgroud)
错误:
消息 207,级别 16,状态 1,第 3
行 列名称“ReferenceToLedgerId”无效
运行以下 SQL 查询时,结果按预期返回:
IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20210612052003_CLedger')
BEGIN
UPDATE LedgerTable SET LedgerId = ReferenceToLedgerId
END;
Run Code Online (Sandbox Code Playgroud)
| 迁移ID | 产品版本 |
|---|---|
| 20210612052003_CLedger | 3.1.15 |
该数据库是 Azure SQL 数据库。脚本在本地 SQL 开发数据库上不会失败。从那时起,已经应用了十几次迁移,直到现在脚本才失败。
以下是创建特定脚本的调用:
SELECT *
FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20210612052003_CLedger'
Run Code Online (Sandbox Code Playgroud)
我尝试将表名和列名放在方括号中,但这没有什么区别(例如......[ReferenceToLedgerId]该脚本在使用 Azure DevOps 版本时失败SQLCMD,并且在使用 Azure Data Studio 时也失败,两者都访问 Azure SQL 数据库。
额外检查
我更改了脚本来进行快速检查:
migrationBuilder.Sql("UPDATE LedgerTable set LedgerId = ReferenceToLedgerId", true);
Run Code Online (Sandbox Code Playgroud)
我得到以下结果:
从第 1 行开始执行查询 #Before IF #After IF 总执行时间:00:00:00.010
如果我取消注释该UPDATE语句,它会再次失败。因此,我只能得出结论,代码路径按预期工作,但服务器仍然检查该列是否存在。我不熟悉 SQL,无法理解为什么会出现这种情况,或者为什么它只在这一行失败,而在 SQL 脚本的其他行中引用列本身而不会失败。
该批处理在每个版本的 SQL Server 上都会失败。例如
use tempdb
go
create table __EFMigrationsHistory(MigrationId nvarchar(200))
create table LedgerTable(LedgerId int)
go
insert into __EFMigrationsHistory(MigrationId) values (N'20210612052003_CLedger')
go
IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20210612052003_CLedger')
BEGIN
UPDATE LedgerTable SET LedgerId = ReferenceToLedgerId
END;
Run Code Online (Sandbox Code Playgroud)
失败与
Msg 207, Level 16, State 1, Line 8
Invalid column name 'ReferenceToLedgerId'.
Run Code Online (Sandbox Code Playgroud)
因为批处理无法解析和编译。在 TSQL 批处理中引用不存在的表或列是不合法的。
您可以通过使用动态 SQL 来解决此问题,这样除非应用迁移,否则不会解析和编译引用不存在列的批处理。
migrationBuilder.Sql("exec('UPDATE LedgerTable set LedgerId = ReferenceToLedgerId')", true);
Run Code Online (Sandbox Code Playgroud)
此处记录了这一点:
提示
当语句必须是 SQL 批处理中的第一个或唯一一个语句时,请使用 EXEC 函数。可能还需要解决幂等迁移脚本中的解析器错误,当表中当前不存在引用的列时可能会发生这些错误。
https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/operations
| 归档时间: |
|
| 查看次数: |
2279 次 |
| 最近记录: |