引进国外KEY约束可能会导致循环或多重级联路径 - 为什么?可能会、路径、国外、级联

2023-09-02 21:07:58 作者:帅萌的酷

我一直在冥思苦想,这一段时间,不能完全弄清楚发生了什么。我有一个包含边的卡实体(通常为2) - 和两个卡和侧面有一个舞台上。我使用的是EF codefirst迁移和迁移是失败与此错误:

I've been wrestling with this for a while and can't quite figure out what's happening. I have a Card entity which contains Sides (usually 2) - and both Cards and Sides have a Stage. I'm using EF Codefirst migrations and the migrations are failing with this error:

引进国外KEY约束'FK_dbo.Sides_dbo.Cards_CardId上   表'边'可能会导致循环或多重级联路径。指定ON   DELETE NO行动或UPDATE没有行动,或者修改其他外国KEY   约束。

Introducing FOREIGN KEY constraint 'FK_dbo.Sides_dbo.Cards_CardId' on table 'Sides' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

下面是我的卡实体:

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

下面是我的侧实体:

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类:

What's odd is that if I add the following to my Stage class:

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

迁移成功运行。如果我打开SSMS,看看表,我可以看到 Stage_StageId 已被添加到(如预期/需要的话),但没有提及舞台(不期望)。

The migration runs successfully. If I open up SSMS and look at the tables, I can see that Stage_StageId has been added to Cards (as expected/desired), however Sides contains no reference to Stage (not expected).

如果我再加入

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

我身边班,我看 StageId 列添加到我的表。

To my Side class, I see StageId column added to my Side table.

这是工作,但现在在我的应用程序,任何引用舞台包含 SideId ,这是在某些情况下完全无关。 我想只要给我实体舞台属性基于上述Stage类的,不污染舞台类参考属性,如果可能的 ...我究竟做错了什么?

This is working, but now throughout my application, any reference to Stage contains a SideId, which is in some cases totally irrelevant. I'd like to just give my Card and Side entities a Stage property based on the above Stage class without polluting the stage class with reference properties if possible... what am I doing wrong?

推荐答案

由于舞台是要求的都是一个一对多的关系,其中舞台是参与将有级联删除默认情况下启用。这意味着,如果删除舞台实体

Because Stage is required all one-to-many relationships where Stage is involved will have cascading delete enabled by default. It means, if you delete a Stage entity

删除将直接级联到 删除将直接级联到因为已与级联所需的一个一对多的关系删除默认启用再次它将再级联从 the delete will cascade directly to Side the delete will cascade directly to Card and because Card and Side have a required one-to-many relationship with cascading delete enabled by default again it will then cascade from Card to Side

所以,你有两个级联删除舞台路径 - 这将导致异常。

So, you have two cascading delete paths from Stage to Side - which causes the exception.

您必须要么使舞台可选的实体中的至少一个(即删除 [必需] 舞台属性的属性)或禁止用流利的API级联删除(无法用数据说明):

You must either make the Stage optional in at least one of the entities (i.e. remove the [Required] attribute from the Stage properties) or disable cascading delete with Fluent API (not possible with data annotations):

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

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