programing

Entity Framework Fluent API를 사용하는 일대일 선택적 관계

nasanasas 2020. 10. 24. 10:20
반응형

Entity Framework Fluent API를 사용하는 일대일 선택적 관계


Entity Framework Code First를 사용하여 일대일 선택적 관계를 사용하려고합니다. 두 개의 엔티티가 있습니다.

public class PIIUser
{
    public int Id { get; set; }

    public int? LoyaltyUserDetailId { get; set; }
    public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
}

public class LoyaltyUserDetail
{
    public int Id { get; set; }
    public double? AvailablePoints { get; set; }

    public int PIIUserId { get; set; }
    public PIIUser PIIUser { get; set; }
}

PIIUser이있을 수 LoyaltyUserDetail있지만 LoyaltyUserDetail이 있어야합니다 PIIUser. 우리는 이러한 유창한 접근 기법을 시도했습니다.

modelBuilder.Entity<PIIUser>()
            .HasOptional(t => t.LoyaltyUserDetail)
            .WithOptionalPrincipal(t => t.PIIUser)
            .WillCascadeOnDelete(true);

이 접근 방식은 테이블에 LoyaltyUserDetailId외래 키를 만들지 않았습니다 PIIUsers.

그 후 다음 코드를 시도했습니다.

modelBuilder.Entity<LoyaltyUserDetail>()
            .HasRequired(t => t.PIIUser)
            .WithRequiredDependent(t => t.LoyaltyUserDetail);

그러나 이번에는 EF가이 두 테이블에 외래 키를 만들지 않았습니다.

이 문제에 대한 아이디어가 있습니까? 엔티티 프레임 워크 유창한 API를 사용하여 어떻게 일대일 선택적 관계를 만들 수 있습니까?


EF Code First 지원 1:11:0..1관계. 후자는 귀하가 찾고있는 것입니다 ( "일대일 또는 일대일").

유창한 시도는 한 경우에는 양쪽 에서 필요 하고 다른 경우에는 양쪽 에서 선택 사항 이라고 말합니다 .

필요한 것은 한쪽 끝 선택 사항 이고 다른 쪽 끝 필수 입니다.

다음은 Programming EF Code First 책의 예입니다.

modelBuilder.Entity<PersonPhoto>()
.HasRequired(p => p.PhotoOf)
.WithOptional(p => p.Photo);

PersonPhoto실체라는 탐색 속성이 PhotoOfA와 그 포인트 Person유형입니다. Person형태라는 탐색 속성이 Photo받는 그 점 PersonPhoto유형입니다.

두 개의 관련 클래스에서 외래 키가 아닌 각 유형의 기본 키 를 사용 합니다 . 즉, LoyaltyUserDetailId또는 PIIUserId속성을 사용하지 않습니다 . 대신 관계 Id는 두 유형 필드에 따라 다릅니다 .

위와 같이 유창한 API를 사용 LoyaltyUser.Id하는 경우 외래 키로 지정할 필요가 없으며 EF가 알아냅니다.

따라서 자신을 테스트 할 코드가 없습니다 (내 머리에서이 작업을 수행하는 것이 싫습니다).

public class PIIUser
{
    public int Id { get; set; }    
    public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
}

public class LoyaltyUserDetail
{
    public int Id { get; set; }
    public double? AvailablePoints { get; set; }    
    public PIIUser PIIUser { get; set; }
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
  modelBuilder.Entity<LoyaltyUserDetail>()
  .HasRequired(lu => lu.PIIUser )
  .WithOptional(pi => pi.LoyaltyUserDetail );
}

즉, LoyaltyUserDetails PIIUser속성은 필수 이고 PIIUser의 LoyaltyUserDetail속성은 선택 사항입니다.

다른 쪽 끝에서 시작할 수 있습니다.

modelBuilder.Entity<PIIUser>()
.HasOptional(pi => pi.LoyaltyUserDetail)
.WithRequired(lu => lu.PIIUser);

이제 PIIUser의 LoyaltyUserDetail속성은 선택 사항이며 LoyaltyUser의 PIIUser속성은 필수 라고 말합니다 .

항상 HAS / WITH 패턴을 사용해야합니다.

HTH 및 FWIW, 일대일 (또는 일대 0 / 일) 관계는 코드에서 먼저 구성해야하는 가장 혼란스러운 관계 중 하나이므로 혼자가 아닙니다! :)


일대 다 관계가있는 경우 LoyaltyUserDetailPIIUser같이 매핑해야합니다.

modelBuilder.Entity<LoyaltyUserDetail>()
       .HasRequired(m => m.PIIUser )
       .WithMany()
       .HasForeignKey(c => c.LoyaltyUserDetailId);

EF는 필요한 모든 외래 키를 만들어야하며 WithMany는 신경 쓰지 않습니다 !


코드에 몇 가지 문제가 있습니다.

1 : 1 관계는 하나이고 : PK <-pk 하나 PK 측 또한 FK이거나, 또는, PK <-fk + UC FK 측 비 PK이며 UC를 갖는다. 귀하의 코드는 FK 를 갖도록 양쪽을 정의함에 따라 FK <-FK 가 있음을 보여 주지만 그것은 잘못되었습니다. I recon PIIUser은 PK 측이고 LoyaltyUserDetailFK 측입니다. 이것은 PIIUserFK 필드가 없다는 것을 의미 LoyaltyUserDetail합니다.

경우] 1 : 1 의 관계가 선택되면, FK 측은, 적어도 1 필드가 널한다.

위의 pswg는 귀하의 질문에 답변했지만 PIIUser에서 FK를 정의한 실수를 저질렀습니다. 물론 위에서 설명한 것처럼 잘못되었습니다. 따라서에서 nullable FK 필드를 LoyaltyUserDetail정의하고에서 속성을 정의하여 FK 필드 LoyaltyUserDetail를 표시하지만에서 FK 필드를 지정하지 마십시오 PIIUser.

PK 측이 아니기 때문에 pswg 게시물 아래에서 위에서 설명한 예외가 발생합니다 (원칙적인 끝).

EF는 고유 한 제약 조건을 처리 할 수 ​​없기 때문에 1 : 1에서 그다지 좋지 않습니다. 저는 코드에 대한 전문가가 아니기 때문에 UC를 만들 수 있는지 여부를 모르겠습니다.

(edit) btw: A 1:1 B (FK) means there's just 1 FK constraint created, on B's target pointing to A's PK, not 2.


Try adding the ForeignKey attribute to the LoyaltyUserDetail property:

public class PIIUser
{
    ...
    public int? LoyaltyUserDetailId { get; set; }
    [ForeignKey("LoyaltyUserDetailId")]
    public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
    ...
}

And the PIIUser property:

public class LoyaltyUserDetail
{
    ...
    public int PIIUserId { get; set; }
    [ForeignKey("PIIUserId")]
    public PIIUser PIIUser { get; set; }
    ...
}

public class User
{
    public int Id { get; set; }
    public int? LoyaltyUserId { get; set; }
    public virtual LoyaltyUser LoyaltyUser { get; set; }
}

public class LoyaltyUser
{
    public int Id { get; set; }
    public virtual User MainUser { get; set; }
}

        modelBuilder.Entity<User>()
            .HasOptional(x => x.LoyaltyUser)
            .WithOptionalDependent(c => c.MainUser)
            .WillCascadeOnDelete(false);

this will solve the problem on REFERENCE and FOREIGN KEYS

when UPDATING or DELETING a record


The one thing that is confusing with above solutions is that the Primary Key is defined as "Id" in both tables and if you have primary key based on the table name it wouldn't work, I have modified the classes to illustrate the same, i.e. the optional table shouldn't define it's own primary key instead should use the same key name from main table.

public class PIIUser
{
    // For illustration purpose I have named the PK as PIIUserId instead of Id
    // public int Id { get; set; }
    public int PIIUserId { get; set; }

    public int? LoyaltyUserDetailId { get; set; }
    public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
}

public class LoyaltyUserDetail
{
    // Note: You cannot define a new Primary key separately as it would create one to many relationship
    // public int LoyaltyUserDetailId { get; set; }

    // Instead you would reuse the PIIUserId from the primary table, and you can mark this as Primary Key as well as foreign key to PIIUser table
    public int PIIUserId { get; set; } 
    public double? AvailablePoints { get; set; }

    public int PIIUserId { get; set; }
    public PIIUser PIIUser { get; set; }
}

And then followed by

modelBuilder.Entity<PIIUser>()
.HasOptional(pi => pi.LoyaltyUserDetail)
.WithRequired(lu => lu.PIIUser);

Would do the trick, the accepted solution fails to clearly explain this, and it threw me off for few hours to find the cause

참고URL : https://stackoverflow.com/questions/18240362/one-to-one-optional-relationship-using-entity-framework-fluent-api

반응형