引入FOREIGN KEY约束可能会导致循环或多个级联path – 为什么?

我一直在摔跤了一段时间,不能完全弄清楚发生了什么。 我有一个包含边的卡实体(通常是2) – 卡和边都有一个阶段。 我正在使用EF Codefirst迁移,并且迁移失败,出现此错误:

在表“边”上引入FOREIGN KEY约束“FK_dbo.Sides_dbo.Cards_CardId”可能会导致循环或多个级联path。 指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束。

这是我的实体:

public class Card { public Card() { Sides = new Collection<Side>(); Stage = Stage.ONE; } [Key] [Required] public virtual int CardId { get; set; } [Required] public virtual Stage Stage { get; set; } [Required] [ForeignKey("CardId")] public virtual ICollection<Side> Sides { get; set; } } 

这是我的Side实体:

 public class Side { public Side() { Stage = Stage.ONE; } [Key] [Required] public virtual int SideId { get; set; } [Required] public virtual Stage Stage { get; set; } [Required] public int CardId { get; set; } [ForeignKey("CardId")] public virtual Card Card { get; set; } } 

这是我的舞台实体:

 public class Stage { // Zero public static readonly Stage ONE = new Stage(new TimeSpan(0, 0, 0), "ONE"); // Ten seconds public static readonly Stage TWO = new Stage(new TimeSpan(0, 0, 10), "TWO"); public static IEnumerable<Stage> Values { get { yield return ONE; yield return TWO; } } public int StageId { get; set; } private readonly TimeSpan span; public string Title { get; set; } Stage(TimeSpan span, string title) { this.span = span; this.Title = title; } public TimeSpan Span { get { return span; } } } 

奇怪的是,如果我将以下内容添加到Stage类中:

  public int? SideId { get; set; } [ForeignKey("SideId")] public virtual Side Side { get; set; } 

迁移成功运行。 如果我打开SSMS并查看表格,我可以看到Stage_StageId已被添加到Cards (按预期/期望),但是Sides包含对Stage引用(不是预期的)。

如果我再添加

  [Required] [ForeignKey("StageId")] public virtual Stage Stage { get; set; } public int StageId { get; set; } 

我的Side类,我看到StageId列添加到我的Side桌。

这是SideId ,但现在在我的应用程序中,任何对Stage引用都包含一个SideId ,在某些情况下,这是完全不相关的。 我想给我的CardSide实体一个基于上述Stage类的Stage属性,如果可能的话,不用污染的引用属性的阶段类 …我做错了什么?

由于Stage是所有Stage所涉及的一对多关系,因此默认情况下会启用级联删除。 这意味着,如果您删除Stage实体

  • 删除将直接级联到Side
  • 删除将直接级联到Card ,因为CardSide有一个必要的一对多的关系,级联删除默认启用,然后它将从CardSide级联

所以,你有两个级联删除path从StageSide – 这会导致exception。

您必须使Stage在至less一个实体中可选(即,从Stage属性中删除[Required]属性),或者使用Fluent API禁用级联删除(数据标注不可能):

 modelBuilder.Entity<Card>() .HasRequired(c => c.Stage) .WithMany() .WillCascadeOnDelete(false); modelBuilder.Entity<Side>() .HasRequired(s => s.Stage) .WithMany() .WillCascadeOnDelete(false); 

我有一个表与其他人有循环关系,我得到了同样的错误。 原来是关于不可空的外键。 如果键不可为空,相关对象必须被删除,循环关系不允许。 所以使用可空的外键。

 [ForeignKey("StageId")] public virtual Stage Stage { get; set; } public int? StageId { get; set; } 

当我从EF7模型迁移到EF6版本时,出现了很多实体的错误。 我不想一次一个地去查看每个实体,所以我用了:

 builder.Conventions.Remove<ManyToManyCascadeDeleteConvention>(); builder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); 

您可以将cascadeDelete设置为false或true(在您的迁移Up()方法中)。 取决于你的要求。

 AddForeignKey("dbo.Stories", "StatusId", "dbo.Status", "StatusID", cascadeDelete: false); 

有人想知道如何在EF核心中做到这一点:

  protected override void OnModelCreating(ModelBuilder modelBuilder) { foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys())) { relationship.DeleteBehavior = DeleteBehavior.Restrict; } ..... rest of the code..... 

我也有这个问题,我用类似的线程回答了这个问题

在我的情况下,我不想删除关键删除的从属logging。 如果在您的情况下,只是将迁移中的布尔值更改为false:

 AddForeignKey("dbo.Stories", "StatusId", "dbo.Status", "StatusID", cascadeDelete: false); 

机会是,如果你正在创build关系抛出这个编译器错误,但是要维护级联删除; 你的关系有问题。

这听起来很奇怪,我不知道为什么,但在我的情况下,因为我的ConnectionString使用“。 在“数据源”属性中。 一旦我将其改为“本地主机”,它就像一个魅力。 没有其他变化是需要的。

.NET Core中,我玩的是所有较高的答案 – 但没有任何成功。 我在数据库结构上进行了很多修改,并且每次都添加新的迁移尝试update-database ,但却收到了同样的错误。

然后,我开始remove-migration ,直到Package Manager Console向我抛出exception:

迁移“20170827183131 _ ***”已经应用于数据库

之后,我成功添加了新的迁移( add-migration )和update-database

所以我的build议是:清除所有的临时迁移,直到你当前的数据库状态。

在.NET Core中,我将onDelete选项更改为ReferencialAction.NoAction

  constraints: table => { table.PrimaryKey("PK_Schedule", x => x.Id); table.ForeignKey( name: "FK_Schedule_Teams_HomeId", column: x => x.HomeId, principalTable: "Teams", principalColumn: "Id", onDelete: ReferentialAction.NoAction); table.ForeignKey( name: "FK_Schedule_Teams_VisitorId", column: x => x.VisitorId, principalTable: "Teams", principalColumn: "Id", onDelete: ReferentialAction.NoAction); });