EF6开启IDENTITY自增时同表自引用外键出现NULL值如何解决?
问题原因
问题根源是自引用表更新时的SQL语句别名歧义:
你用到的自定义迁移操作生成的自引用外键更新语句没有为同名表设置区分别名,SQL解析时会将子查询的匹配条件old_KomponenteId = Komponente.OtherKomponenteId识别为「内层查询表的old_KomponenteId = 内层查询表的OtherKomponenteId」,而非预期的「内层查询表的old_KomponenteId = 外层待更新表的OtherKomponenteId」,匹配不到有效数据时子查询返回NULL,最终导致所有OtherKomponenteId被覆盖为NULL。
解决方案
方案1:修改自定义迁移操作的SQL生成逻辑(推荐,一劳永逸)
找到对应ChangeIdentity扩展的迁移操作实现类,调整依赖列UPDATE语句的生成逻辑:
当检测到主表和依赖表为同一表时,强制为外层更新表、内层查询表分别设置不同别名,生成的SQL格式如下:
UPDATE K1 SET OtherKomponenteId = ( SELECT TOP 1 K2.KomponenteId FROM Komponente K2 WHERE K2.old_KomponenteId = K1.OtherKomponenteId ) FROM Komponente K1
方案2:手动编写本次迁移的SQL步骤
如果不想调整底层迁移工具代码,可直接替换当前迁移的ChangeIdentity调用,手动分步实现逻辑:
public override void Up() { // 1. 重命名原主键为备份字段 RenameColumn("dbo.Komponente", "KomponenteId", "old_KomponenteId"); // 2. 添加新的自增主键列 AddColumn("dbo.Komponente", "KomponenteId", c => c.Long(nullable: false, identity: true)); // 3. 重建主键约束 DropPrimaryKey("dbo.Komponente"); AddPrimaryKey("dbo.Komponente", "KomponenteId"); // 4. 删除旧的自引用外键约束 DropForeignKey("dbo.Komponente", "OtherKomponenteId", "dbo.Komponente"); // 5. 执行带别名的更新语句,修复自引用外键值 Sql(@"UPDATE K1 SET OtherKomponenteId = ( SELECT TOP 1 K2.KomponenteId FROM Komponente K2 WHERE K2.old_KomponenteId = K1.OtherKomponenteId ) FROM Komponente K1"); // 6. 重建新的自引用外键约束 AddForeignKey("dbo.Komponente", "OtherKomponenteId", "dbo.Komponente", "KomponenteId"); // 7. 删除原主键备份字段 DropColumn("dbo.Komponente", "old_KomponenteId"); }
内容的提问来源于stack exchange,提问作者Saibamen
相关产品推荐
相关产品推荐

