.NET 6创建数据库外键约束报错及级联删除需求咨询
解决EF Core外键约束的循环/多极联路径错误
错误信息
在表'ContractTypeTwos'上引入外键约束'FK_ContractTypeTwos_ContractTypeOnes_ContractTypeOneId'可能导致循环或多个级联路径。请指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他外键约束。
无法创建约束或索引。请查看之前的错误。
需求
- 删除
ContractTypeOne时,自动级联删除关联的ContractTypeTwo - 删除
ContractTypeOne时,不删除关联的Contract
相关代码
核心模型代码
namespace ContractAppAPI.Models { public class Contract { public int Id { get; set; } public int ContractNumber { get; set; } public string Name { get; set; } public DateTime DateOfConclusion { get; set; } public string Description { get; set; } public decimal Value { get; set; } public string Contractor { get; set; } public string Signatory { get; set; } public Boolean HasPdf { get; set; } public ContractTypeOne ContractTypeOne { get; set; } public ContractTypeTwo ContractTypeTwo { get; set; } public ICollection<ContractPdf> ContractPdfs { get; set; } public ICollection<AnnexToTheContract> AnnexToTheContracts { get; set; } } public class ContractTypeOne { public int Id { get; set; } public string Name { get; set; } public ICollection<Contract> Contracts { get; set; } public ICollection<ContractTypeTwo> ContractTypeTwos { get; set; } } public class ContractTypeTwo { public int Id { get; set; } public string Name { get; set; } public int ContractTypeOneId { get; set; } public ContractTypeOne ContractTypeOne { get; set; } public ICollection<Contract> Contracts { get; set; } } }
当前实体配置代码
modelBuilder.Entity<ContractTypeOne>() .HasMany(cto => cto.ContractTypeTwos) .WithOne(ctt => ctt.ContractTypeOne) .HasForeignKey(ctt => ctt.ContractTypeOneId) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity<ContractTypeTwo>() .HasOne(ctt => ctt.ContractTypeOne) .WithMany(cto => cto.ContractTypeTwos) .HasForeignKey(ctt => ctt.ContractTypeOneId) .OnDelete(DeleteBehavior.NoAction);
其他关联模型代码
AnnexToTheContract
namespace ContractAppAPI.Models { public class AnnexToTheContract { public int Id { get; set; } public int AnnexNumber { get; set; } public string Name { get; set; } public DateTime DateOfConclusion { get; set; } public string Description { get; set; } public string Contractor { get; set; } public string Signatory { get; set; } public Boolean HasPdf { get; set; } = false; public int ContractId { get; set; } public Contract Contract { get; set; } public ICollection<Pdf> Pdfs { get; set; } } }
ContractPdf
using System.ComponentModel.DataAnnotations.Schema; namespace ContractAppAPI.Models { public class ContractPdf { public int Id { get; set; } [NotMapped] public IFormFile? File { get; set; } public string FilePath { get; set; } public int ContractId { get; set; } public Contract Contract { get; set; } } }
using System.ComponentModel.DataAnnotations.Schema; namespace ContractAppAPI.Models { public class Pdf { public int Id { get; set; } [NotMapped] public IFormFile? File { get; set; } public string FilePath { get; set; } public int AnnexToTheContractId { get; set; } public AnnexToTheContract AnnexToTheContract { get; set; } } }
问题原因
报错核心是多极联路径冲突:
删除ContractTypeOne时,EF Core默认生成两条级联删除路径到Contract:
ContractTypeOne→ContractContractTypeOne→ContractTypeTwo→Contract
同时重复配置了ContractTypeOne与ContractTypeTwo的外键关系,导致配置冲突。
解决步骤
- 移除重复的外键配置,只保留一组
ContractTypeOne与ContractTypeTwo的关系配置并设置级联删除。 - 修改
Contract与两类合同类型的关系,禁止级联删除,避免多路径冲突。
修改后的实体配置代码
// 配置ContractTypeOne与ContractTypeTwo的级联删除 modelBuilder.Entity<ContractTypeOne>() .HasMany(cto => cto.ContractTypeTwos) .WithOne(ctt => ctt.ContractTypeOne) .HasForeignKey(ctt => ctt.ContractTypeOneId) .OnDelete(DeleteBehavior.Cascade); // 配置Contract与ContractTypeOne的关系,禁止级联删除 modelBuilder.Entity<Contract>() .HasOne(c => c.ContractTypeOne) .WithMany(cto => cto.Contracts) .OnDelete(DeleteBehavior.Restrict); // 配置Contract与ContractTypeTwo的关系,禁止级联删除 modelBuilder.Entity<Contract>() .HasOne(c => c.ContractTypeTwo) .WithMany(ctt => ctt.Contracts) .OnDelete(DeleteBehavior.Restrict);
说明
DeleteBehavior.Cascade:删除父实体时自动删除关联子实体,满足删除ContractTypeOne时删除ContractTypeTwo的需求。DeleteBehavior.Restrict:删除父实体时,若存在关联子实体则数据库抛出错误阻止删除,既确保Contract不会被级联删除,也解决了多路径冲突。若需更宽松限制,可改用DeleteBehavior.NoAction,此时删除父实体不影响子实体,但需自行处理子实体的无效外键数据一致性问题。
内容的提问来源于stack exchange,提问作者Bartek S
相关产品推荐
相关产品推荐

