EF Core 2.0.1可选关联生成Restrict而非ClientSetNull原因咨询
你遇到的情况其实是EF Core 2.0.1版本的一个已知bug——虽然官方文档明确说可选关联的默认删除行为是ClientSetNull,但当你用数据注解配置双向可选关联时(就像你模型里恐龙和猎物的双向导航+可空外键),EF Core的模型构建器会“失忆”,错误地沿用了2.0之前版本的默认行为Restrict,导致生成的迁移里出现了onDelete: ReferentialAction.Restrict。
为什么会触发这个bug?
EF Core 2.0新增ClientSetNull作为可选关联的默认,但在2.0.1版本中,当模型同时满足以下两个条件时,bug就会出现:
- 关联是双向的(两边都有导航属性:恐龙的
YummyPunyPrey集合,猎物的BigAwesomeDinosaurWithTeeth导航) - 外键属性是可空类型(
Guid? BigAwesomeDinosaurWithTeethId)
这种情况下,模型构建器无法正确识别关联的可选性,直接回退到了旧版本的Restrict默认。
解决办法,选一个就行
1. 用Fluent API显式配置(最稳妥)
绕开数据注解的bug,直接在DbContext的OnModelCreating里明确指定删除行为:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<YummyPunyPrey>() .HasOne(prey => prey.BigAwesomeDinosaurWithTeeth) .WithMany(dino => dino.YummyPunyPrey) .HasForeignKey(prey => prey.BigAwesomeDinosaurWithTeethId) .OnDelete(DeleteBehavior.ClientSetNull); }
这样生成的迁移就会正确对应ClientSetNull的行为:数据库层面不添加ON DELETE约束,EF在内存中将关联猎物的外键设为null。
2. 升级EF Core版本到2.0.2+
微软在2.0.2补丁里修复了这个bug,升级后不用改任何模型代码,重新生成迁移就会自动使用ClientSetNull的默认行为。
3. 临时方案:手动改迁移文件(不推荐)
如果你暂时没法升级或改代码,可以手动把迁移里的onDelete: ReferentialAction.Restrict改成ReferentialAction.NoAction——这对应ClientSetNull的数据库行为。但要注意,后续重新生成迁移时这个修改可能会被覆盖,所以还是前两种方法更靠谱。
内容的提问来源于stack exchange,提问作者David Moores

