引入外键约束可能会导致循环或多个级联路径 - 为什么?

20 浏览
0 Comments

引入外键约束可能会导致循环或多个级联路径 - 为什么?

我已经苦思冥想了一段时间,但仍然无法弄清楚发生了什么。我有一个包含Side(通常为2个)的Card实体 - Card和Side都有一个Stage。我正在使用EF Codefirst迁移,但迁移失败并显示以下错误:\n引入FOREIGN KEY约束\'FK_dbo.Sides_dbo.Cards_CardId\'到\'table \'Sides\'可能会导致循环或多个级联路径。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束。\n这是我的Card实体:\n

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

\n这是我的Side实体:\n

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; }
}

\n这是我的Stage实体:\n

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 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; } }
}

\n奇怪的是,如果我在我的Stage类中添加以下内容:\n

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

\n迁移将成功运行。如果我打开SSMS并查看表,我可以看到Stage_StageId已添加到Cards(如预期/所需),但Sides不包含对Stage的引用(不符合预期)。\n如果我接下来在我的Side类中添加:\n

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

\n我会在我的Side表中看到StageId列被添加。\n这是有效的,但现在在我的应用程序中,任何对Stage的引用都包含一个SideId,在某些情况下完全无关紧要。如果可能的话,我希望只给我的CardSide实体一个基于上面的Stage类的Stage属性,而不会污染stage类与引用属性...我做错了什么?

0
0 Comments

在EF Core中,当引入外键约束时,可能会出现循环或多个级联路径的问题。解决这个问题的方法是通过在OnModelCreating方法中修改DeleteBehavior属性,将级联删除行为设置为Restrict。

在代码中,可以通过以下方式实现将所有关系的级联删除行为设置为Restrict:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
    {
        relationship.DeleteBehavior = DeleteBehavior.Restrict;
    }
    ..... 其他代码.....
}

这将关闭所有关系的级联删除功能。对于某些用例,级联删除可能是一个期望的功能。

另一种解决方法是在关系配置中使用OnDelete方法将级联删除行为设置为Restrict,例如:

builder.HasOne(x => x.Stage).WithMany().HasForeignKey(x => x.StageId).OnDelete(DeleteBehavior.Restrict);

在这个例子中,builder是一个IEntityTypeConfiguration的实例。在最新的EF Core版本中,可能需要使用builder.Entity方法来替代builder.HasOne()方法。

总之,通过修改级联删除行为,可以解决Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths的问题。这样可以避免出现循环或多个级联路径的情况,从而确保数据库的完整性和一致性。

0
0 Comments

当在数据库中使用外键约束时,有可能会出现“Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths”这个错误。这个错误的出现原因是由于存在循环关系或多个级联路径。

解决这个问题的方法是将外键设置为可为空。如果外键不可为空,则需要删除相关对象,而循环关系不允许这样做。因此,需要将外键设置为可为空。

在代码中,可以使用int?来表示可为空的外键,而不是使用int来表示不可为空的外键。此外,还需要将外键属性上的[Required]标签移除,以确保外键可为空。

尝试关闭级联删除并不能解决这个问题,而将外键设为可为空则可以解决这个问题。

需要注意的是,如果不希望允许将外键设置为null(在原问题中,Stage是一个必填字段),则不应该使用这种解决方法。

当在使用外键约束时出现“Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths”错误时,可以通过将外键设置为可为空来解决这个问题。

0
0 Comments

引入外键约束可能会导致循环或多重级联路径-为什么会出现这个问题?

这个问题的出现是因为Stage是必需的,与Stage相关的所有一对多关系默认都启用了级联删除。这意味着,如果你删除一个Stage实体:

  • 删除将直接级联到Side
  • 删除将直接级联到Card,因为CardSide之间有一个必需的一对多关系,并且默认情况下启用了级联删除,所以从CardSide将再次级联

所以,从StageSide有两条级联删除路径,这导致了异常的出现。

你必须要么使Stage在至少一个实体中是可选的(即从Stage属性中删除[Required]属性),要么使用Fluent API禁用级联删除(无法通过数据注释实现):

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

谢谢Slauma。如果我像你上面演示的那样使用Fluent API,其他字段是否保留其级联删除行为?例如,我仍然希望在删除卡片时删除边。

: 是的,它只会影响从Stage开始的关系。其他关系保持不变。

有没有办法知道哪些属性导致了错误?我遇到了相同的问题,查看我的类,我看不到循环在哪里。

这是他们实现的限制吗?对我来说,Stage的删除直接级联到Side和通过Card级联看起来是没问题的。

假设我们将CascadeOnDelete设置为false。然后我们删除了与其中一条Card记录相关联的Stage记录。Card.Stage(FK)会发生什么?它保持不变吗?还是设置为Null?

如果您希望实现这种级联行为怎么办?在层次结构实体中,预期会在层次结构中和引用实体被删除时进行级联。

在EF Core 5中使用.OnDelete(DeleteBehavior.NoAction)

我不明白你的回答-我理解为Stage和Side有一个1对1的关系,而不是1对多。

此外,最新的EF Core不再具有WillCascadeOnDelete()。我认为你现在需要使用OnDelete()。

0