EF Core 默认会在某些关系(如必选外键)中启用级联删除,这可能导致意外删除大量关联数据。禁用它不难,关键是统一、明确地控制所有外键的行为,而不是靠删导航属性或改数据库。
全局统一设为 Restrict
最常用也最稳妥的方式是在 OnModelCreating 中遍历所有外键,强制设为 DeleteBehavior.Restrict:
该行为表示:尝试删除被引用的主表记录时,若子表仍有数据,直接抛出异常(违反约束),不会自动删子项也不会设外键为 null 适用于所有外键,无论是否可空、是否是一对多或一对一 代码简洁,一次配置,全模型生效 示例:protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
foreach (var fk in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
{
fk.DeleteBehavior = DeleteBehavior.Restrict;
}
}
按需单独配置某关系
如果只希望禁用特定一对关系的级联(比如 Department 和 Instructor),可在 Fluent API 中精准设置:
在 HasOne 或 HasMany 配置链末尾加 OnDelete(DeleteBehavior.Restrict) 注意:必须在关系定义之后立即调用,否则无效 适合局部调整,不影响其他实体 示例:modelBuilder.Entity<Department>()
.HasOne(d => d.Instructor)
.WithMany()
.HasForeignKey(d => d.InstructorId)
.OnDelete(DeleteBehavior.Restrict);
避免误用 ClientSetNull 和 NoAction
这两个行为容易混淆,实际效果不同:
ClientSetNull:EF Core 尝试把子项外键设为 null(仅限可空外键),失败则报错;不是禁用级联,而是换种删除策略 NoAction:不生成任何外键操作语句,完全交由数据库约束处理;但某些数据库(如 SQL Server)默认仍会级联,不可靠 真正“禁用级联”的推荐值只有 Restrict(EF Core 5+)或 Restrict 的等效写法迁移文件里也要同步修正
如果你已有生成好的迁移,其中外键定义含
CASCADE,光改代码不够: 手动编辑迁移文件中的
ForeignKey定义,把
onDelete: ReferentialAction.Cascade改成
onDelete: ReferentialAction.Restrict再运行
dotnet ef migrations add FixCascade确保新迁移不含级联 否则下次更新数据库时,旧迁移仍会创建带级联的外键
基本上就这些。核心就一条:用 Restrict 替代默认行为,并确保代码和迁移一致。不复杂但容易忽略迁移层。
