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:1
및 1:0..1
관계. 후자는 귀하가 찾고있는 것입니다 ( "일대일 또는 일대일").
유창한 시도는 한 경우에는 양쪽 에서 필요 하고 다른 경우에는 양쪽 에서 선택 사항 이라고 말합니다 .
필요한 것은 한쪽 끝 은 선택 사항 이고 다른 쪽 끝 은 필수 입니다.
다음은 Programming EF Code First 책의 예입니다.
modelBuilder.Entity<PersonPhoto>()
.HasRequired(p => p.PhotoOf)
.WithOptional(p => p.Photo);
PersonPhoto
실체라는 탐색 속성이 PhotoOf
A와 그 포인트 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 / 일) 관계는 코드에서 먼저 구성해야하는 가장 혼란스러운 관계 중 하나이므로 혼자가 아닙니다! :)
일대 다 관계가있는 경우 LoyaltyUserDetail
와 PIIUser
같이 매핑해야합니다.
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 측이고 LoyaltyUserDetail
FK 측입니다. 이것은 PIIUser
FK 필드가 없다는 것을 의미 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
'programing' 카테고리의 다른 글
hg log-마지막 5 개의 로그 항목을 가져 오는 방법은 무엇입니까? (0) | 2020.10.24 |
---|---|
특히 Node.js가 Apache보다 더 확장 가능한 이유는 무엇입니까? (0) | 2020.10.24 |
React Native의 Absolute 및 Flexbox (0) | 2020.10.23 |
Matlab 플롯에서 글꼴 크기 변경 (0) | 2020.10.23 |
전체 페이지를 이동시키는 ScrollIntoView () (0) | 2020.10.23 |