[.net] FOREIGN KEY 제약 조건을 도입하면 사이클 또는 여러 계단식 경로가 발생할 수 있습니다. 왜 그렇습니까?

나는 이것을 잠시 동안 레슬링 해 왔으며 무슨 일이 일어나고 있는지 알 수 없습니다. 사이드 (일반적으로 2)를 포함하는 카드 엔티티가 있으며 카드와 사이드 모두 스테이지가 있습니다. EF Codefirst 마이그레이션을 사용하고 있으며이 오류로 마이그레이션이 실패합니다.

테이블 ‘Sides’에 FOREIGN KEY 제약 조건 ‘FK_dbo.Sides_dbo.Cards_CardId’를 도입하면 사이클 또는 여러 계단식 경로가 발생할 수 있습니다. 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; }
}

실체는 다음과 같습니다 .

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

이상한 점은 스테이지 클래스에 다음을 추가하면 다음과 같습니다.

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

내 사이드 ​​클래스에 StageId열이 추가 된 것을 볼 수 있습니다.Side 테이블에 있습니다.

이것은 작동하지만 이제는 내 응용 프로그램 전체에서에 대한 모든 참조가 Stage포함되어 있으며 SideId경우에 따라 전혀 관련이 없습니다. 난 그냥 내주고 싶습니다 CardSide단체 Stage참조 속성 가능한 경우와 무대 클래스 오염없이 무대 위의 클래스를 기반으로 재산을 … 내가 잘못을하고있는 중이 야 무엇을?



답변

Stageis가 필요 하기 때문에 Stage관련된 모든 일대 다 관계에는 기본적으로 계단식 삭제가 사용됩니다. Stage엔터티 를 삭제하면

  • 삭제는 Side
  • 삭제가 직접 연쇄 것 Card때문 CardSide이 삭제 다시는 그때부터 단계적으로합니다 기본적으로 활성화 계단식으로 일대 다 관계를 필요 CardSide

따라서 두 개의 계단식 삭제 경로가 있습니다 Stage.Side -예외가 발생합니다.

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


답변

나는 다른 사람들과 순환 관계가있는 테이블을 가지고 있었고 같은 오류가 발생했습니다. 그것은 nullable이 아닌 외래 키에 관한 것입니다. 키가 널 입력 가능하지 않은 경우 관련 오브젝트를 삭제해야하며 순환 관계에서는이를 허용하지 않습니다. 따라서 널 입력 가능 외래 키를 사용하십시오.

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


답변

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.....


답변

EF7 모델에서 EF6 버전으로 마이그레이션 할 때 많은 엔티티에 대해이 오류가 발생했습니다. 한 번에 하나씩 각 엔티티를 통과하고 싶지는 않았으므로 다음을 사용했습니다.

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


답변

마이그레이션 Up () 메서드에서 cascadeDelete를 false 또는 true로 설정할 수 있습니다. 요구 사항에 따라 다릅니다.

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


답변

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


답변

나는이 문제도 가지고 있었고 비슷한 스레드 에서이 답변으로 즉시 해결했습니다.

필자의 경우 키 삭제시 종속 레코드를 삭제하고 싶지 않았습니다. 이 상황에서 마이그레이션의 부울 값을 false로 변경하면됩니다.

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

이 컴파일러 오류를 발생시키는 관계를 작성하지만 계단식 삭제를 유지하려는 경우가 있습니다. 당신은 당신의 관계에 문제가 있습니다.