EF Core 3.1.7 테이블의 여러 1 : 1 관계에 대한 데이터 주석

Aug 17 2020

EF Core 3.11.7이이를 이해하고 마이그레이션을 빌드 할 수 있도록 둘 이상의 1 : 1 관계를 매핑하는 데이터 주석을 파악하는 데 문제가 있습니다.

Person 테이블과 Notes 테이블이 있습니다. Person에는 0 : M Notes 관계가 있습니다. 개인 레코드에는 0 개 이상의 메모가있을 수 있습니다.

메모 테이블에는 사람인 CreatedBy 필드가 있습니다. 또한 사람인 LastEditedBy 필드도 있습니다. EF는 Note.CreatedBy에 대한 관계를 구성하는 방법에 대해 계속해서 공격하고 있습니다. 이것이 EF가 아닌 경우 두 필드 모두 적절한 개인 레코드의 PersonID가있는 int가됩니다. 데이터 주석을 선호하는 방식으로 EF Core에이를 설명하는 방법은 무엇입니까?

마이그레이션을 만들려고하면 실패하고 다음과 같이 표시됩니다. System.InvalidOperationException : 'Person'유형의 탐색 속성 'Note.CreatedBy'가 나타내는 관계를 확인할 수 없습니다. 관계를 수동으로 구성하거나 '[NotMapped]'속성을 사용하거나 'OnModelCreating'에서 'EntityTypeBuilder.Ignore'를 사용하여이 속성을 무시하십시오.

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Linq;
    using System.Threading.Tasks;

namespace VetReg.Domain.Model
{
    public class Family
    {
        public int FamilyID { get; set; } = -1;
        public string FamilyName { get; set; }
        public List<Pet> Pets { get; set; } = new List<Pet>();
        public List<PersonFamily> People { get; set; }
        public int AddressID { get; set; } = -1;
        public List<Note> Notes { get; set; }
    }

    public class Person
    {
        public int PersonID { get; set; }
        public string LastName { get; set; }
        public string FirstName { get; set; }
        public DateTime? Birthdate { get; set; }
        public string Password { get; set; }
        public List<PersonFamily> Families { get; set; }
        public List<Note> Notes { get; set; }
    } // class People

    public class Note
    {
        public int NoteID { get; set; }

        public int CreatedByID { get; set; }

        [ForeignKey("CreatedByID")]
        public Person CreatedBy { get; set; }
        public DateTime DateCreated { get; set; }

        public int LastEditByID { get; set; }

        [ForeignKey("LastEditByID")]
        public Person LastEditBy { get; set; }
        public DateTime? LastEditDate { get; set; }
        public string NoteText { get; set; }
    }

    public class PersonFamily
    {
        public int PersonID { get; set; }
        public int FamilyID { get; set; }
        public Person Person { get; set; }
        public Family Family { get; set; }
    }

}

답변

IvanStoev Aug 17 2020 at 15:11

질문은 (그리고 이것이 EF가 관계를 자동으로 결정하는 것을 불가능하게 만드는 것입니다) Person.Notes그리고 Note.CreatedBy/ Note.LastEditBy-아마 사이의 관계는 무엇 입니까? M의 관계 : 당신은 0이 말한 PersonNote- 사람과 관련된 노트, 3 FKS과 사람, 잠재적으로 리드에 의해 편집 사람 및 메모에 의해 생성 한 메모 만이 3 일대 다 관계가 잠재적으로 있다는 것을 참고 메모에있는 사람.

또한 탐색 속성은 필요하지 않지만 존재하는 경우 쌍을 이루어야합니다.

사이에 관계가없는 즉, 당신이 세 관계를 원하는 가정 Note.CreatedBy/ Note.LastEditByPerson.Notes, 그 EF 말할 필요 Note.CreatedByNote.LastEditBy대응에 (일명 역) 탐색 속성이 없습니다 Person. 데이터 주석으로는 불가능합니다. 이 목적을 위해 사용 가능한 유일한 데이터 주석은 [InverseProperty(...)]비어있는 / 널 문자열 이름을 허용하지 않으므로 여기에서 필요한 항목에 사용할 수 없습니다.

또한 현재를 해결 한 후 발생하는 또 다른 문제가 있습니다.이 문제는 데이터 주석으로도 해결할 수 없습니다. 에서까지 여러 필수 (기본적으로 계단식 삭제) 관계가 Person있으므로 NoteSqlServer에 유명한 "주기 또는 다중 계단식 경로"문제가 발생하고 계단식 삭제 중 하나 이상을 해제해야합니다.

따라서 해당 모델에는 다음과 같은 최소한의 유창한 구성이 필요합니다.

modelBuilder.Entity<Note>()
    .HasOne(e => e.CreatedBy)
    .WithMany()
    .OnDelete(DeleteBehavior.Restrict);

modelBuilder.Entity<Note>()
    .HasOne(e => e.LastEditBy)
    .WithMany()
    .OnDelete(DeleteBehavior.Restrict);

원래 문제의 핵심은 HasOne/ WithMany쌍입니다. 이렇게하면 EF Core는 매핑되지 않은 Person.Notes컬렉션을 "PersonId"라는 역방향 탐색 속성과 섀도 FP 속성 (및 열)이없는 세 번째 선택적 관계에 자동으로 매핑합니다.

modelBuilder.Entity<Person>()
    .HasMany(e => e.Notes)
    .WithOne()
    .HasForeignKey("PersonId");

다중 계단식 경로의 두 번째 문제와 관련하여 Restrict비 계단식 옵션 또는 최신 ClientCascade. 그리고 그것은 "계단 경로"를 깨는 즉시 관계 중 하나에 대한 것일 수 있습니다 (분명히 모델에서 요구하기 때문에 사이클을 깨뜨릴 수 없습니다).