.net 引入 FOREIGN KEY 约束可能会导致循环或多个级联路径 - 为什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17127351/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 12:19:07  来源:igfitidea点击:

Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths - why?

.netentity-frameworkforeign-keysef-code-firstentity-framework-4

提问by SB2055

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:

我一直在努力解决这个问题,无法弄清楚发生了什么。我有一个包含 Sides(通常为 2)的 Card 实体 - Cards 和 Sides 都有一个 Stage。我正在使用 EF Codefirst 迁移并且迁移失败并出现此错误:

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.

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

Here's my Cardentity:

这是我的Card实体:

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

Here's my Sideentity:

这是我的实体:

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

}

And here's my Stageentity:

这是我的舞台实体:

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

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

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

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

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

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

If I then add

如果我再添加

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

To my Side class, I see StageIdcolumn added to my Sidetable.

对于我的 Side 类,我看到StageId添加到我的Side表中的列。

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

这是有效的,但现在在我的整个应用程序中,对Stage包含 a 的任何引用SideId,在某些情况下完全不相关。 如果可能的话,我只想给我的CardSide实体一个Stage基于上述 Stage 类的属性,而不用参考属性污染舞台类......我做错了什么?

回答by Slauma

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

因为Stagerequired,所有Stage涉及到的一对多关系都会默认启用级联删除。这意味着,如果您删除一个Stage实体

  • the delete will cascade directly to Side
  • the delete will cascade directly to Cardand because Cardand Sidehave a required one-to-many relationship with cascading delete enabled by default again it will then cascade from Cardto Side
  • 删除将直接级联到 Side
  • 删除将直接级联到Cardand 因为Card并且Side与默认情况下再次启用级联删除具有必需的一对多关系,然后它将级联从CardSide

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

因此,您有两个来自Stageto 的级联删除路径Side- 这会导致异常。

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

您必须Stage在至少一个实体中设置可选(即[Required]Stage属性中删除属性)或使用 Fluent API 禁用级联删除(无法使用数据注释):

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

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

回答by Cem Mutlu

I had a table that had a circular relationship with others and i was getting the same error. Turns out it is about the foreign key which was not nullable. If key is not nullable related object must be deleted and circular relations doesnt allow that. So use nullable foreign key.

我有一张与其他人有循环关系的桌子,但我遇到了同样的错误。原来它是关于不可为空的外键。如果键不可为空,则必须删除相关对象,并且循环关系不允许这样做。所以使用可为空的外键。

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

回答by Nexus23

Anybody wondering how to do it in EF core:

任何想知道如何在 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.....

回答by Sean

I was getting this error for lots of entities when I was migrating down from an EF7 model to an EF6 version. I didn't want to have to go through each entity one at a time, so I used:

当我从 EF7 模型向下迁移到 EF6 版本时,很多实体都收到此错误。我不想一次遍历每个实体,所以我使用了:

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

回答by Musakkhir Sayyed

You can set cascadeDelete to false or true (in your migration Up() method). Depends upon your requirement.

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

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

回答by Mike Jones

In .NET Core I changed the onDelete option to ReferencialAction.NoAction

在 .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);
            });

回答by jonc.js

I had this issue also, I solved it instantly with this answer from a similar thread

我也有这个问题,我用类似线程的这个答案立即解决了它

In my case, I didn't want to delete the dependent record on key deletion. If this is the case in your situation just simply change the Boolean value in the migration to false:

就我而言,我不想在删除密钥时删除相关记录。如果您的情况是这种情况,只需将迁移中的布尔值更改为 false:

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

Chances are, if you are creating relationships which throw this compiler error but DO want to maintain cascade delete; you have an issue with your relationships.

很有可能,如果您正在创建引发此编译器错误的关系,但确实想要维护级联删除;你的人际关系有问题。

回答by Usman Khan

I fixed this. When you add the migration, in the Up() method there will be a line like this:

我解决了这个问题。添加迁移时,在 Up() 方法中会有这样一行:

.ForeignKey("dbo.Members", t => t.MemberId, cascadeDelete:True)

If you just delete the cascadeDelete from the end it will work.

如果你只是从最后删除级联删除它会起作用。

回答by sgrysoft

Just for documentation purpose, to someone that comes on the future, this thing can be solved as simple as this, and with this method, you could do a method that disabled one time, and you could access your method normally

只是为了文档目的,对于未来的人来说,这件事可以像这样简单地解决,使用这种方法,你可以做一个禁用一次的方法,你可以正常访问你的方法

Add this method to the context database class:

将此方法添加到上下文数据库类:

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
    modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}

回答by Niroshan Kumarasamy

The simple way is to, Edit your migration file (cascadeDelete: true)into (cascadeDelete: false)then after assign the Update-Database command in your Package Manager Console.if it's problem with your last migration then all right. Otherwise check your earlier migration history, copy those things, paste into your last migration file, after that do it the same thing. it perfectly works for me.

简单的方法是,在包管理器控制台中分配 Update-Database 命令后,将迁移文件编辑(cascadeDelete: true)(cascadeDelete: false)then。如果上次迁移有问题,那么没问题。否则检查您之前的迁移历史记录,复制这些内容,粘贴到您的最后一个迁移文件中,然后再做同样的事情。它非常适合我。