IT

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

lottoking 2020. 3. 25. 08:37
반응형

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

이상한 점은 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; }

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

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


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

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

그래서, 당신은 두 계단식 삭제 경로가 StageSide예외를 발생 -.

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

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

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

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

나는 이것을 고쳤다. 마이그레이션을 추가하면 Up () 메서드에 다음과 같은 줄이 있습니다.

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

일단 cascadeDelete를 삭제하면 작동합니다.


문서화 목적으로, 미래에 온 사람에게이 문제는 이렇게 간단하게 해결 될 수 있으며,이 방법을 사용하면 한 번 비활성화 된 방법을 사용할 수 있으며 일반적으로 방법에 액세스 할 수 있습니다

이 메소드를 컨텍스트 데이터베이스 클래스에 추가하십시오.

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

이상하게 들리지만 이유를 모르겠지만 ConnectionString이 "."를 사용했기 때문에 발생했습니다. "데이터 소스"속성에서. 일단 "localhost"로 변경하면 매력처럼 작동했습니다. 다른 변경은 필요하지 않았습니다.


기존 답변은 훌륭합니다. 다른 이유로 인해이 오류가 발생했다고 덧붙였습니다. 기존 DB에서 초기 EF 마이그레이션을 만들고 싶었지만 -IgnoreChanges 플래그를 사용하지 않고 빈 데이터베이스에 Update-Database 명령을 적용했습니다 (기존의 실패에도 적용).

대신 현재 db 구조가 현재 구조 일 때이 명령을 실행해야했습니다.

Add-Migration Initial -IgnoreChanges

db 구조에 실제 문제가있을 수 있지만 한 번에 한 단계 씩 세계를 구하십시오 ...


에서 .NET 핵심 나는 모든 상위 답변을했다 -하지만 어떤 성공없이. DB 구조를 많이 변경했으며에 대해 새로운 마이그레이션을 시도 할 때마다 update-database동일한 오류가 발생했습니다.

그런 다음 Package Manager Console에서 예외가 발생할 remove-migration때까지 하나씩 시작했습니다 .

'20170827183131 _ ***'마이그레이션이 이미 데이터베이스에 적용되었습니다

그 후 새 마이그레이션 ( add-migration)을 추가 하고 update-database 성공적으로

따라서 내 제안은 다음과 같습니다. 현재 DB 상태가 될 때까지 모든 임시 마이그레이션을 지우십시오.


위에서 언급 한 해결책 중 어느 것도 나를 위해 일하지 않았습니다. 내가해야 할 일은 필요하지 않은 외래 키 (또는 null이 아닌 열 키)에 nullable int (int?)를 사용한 다음 일부 마이그레이션을 삭제하는 것입니다.

마이그레이션을 삭제하여 시작한 다음 nullable int를 시도하십시오.

문제는 수정과 모델 디자인이었습니다. 코드 변경이 필요하지 않았습니다.


간단한 방법은 패키지 관리자 콘솔에서 Update-Database 명령을 할당 한 후 마이그레이션 파일 (cascadeDelete: true)편집 (cascadeDelete: false)한 다음 마지막 마이그레이션에 문제가있는 경우입니다. 그렇지 않으면 이전 마이그레이션 기록을 확인하고 해당 항목을 복사 한 다음 마지막 마이그레이션 파일에 붙여 넣은 후 동일한 작업을 수행하십시오. 그것은 나를 위해 완벽하게 작동합니다.

참고 : https://stackoverflow.com/questions/17127351/introducing-foreign-key-constraint-may-cause-cycles-or-multiple-cascade-paths

반응형