Entity Framework
Entity Framework와의 매핑 관계 코드 우선 : 일대일 및 변형
수색…
소개
이 항목에서는 Entity Framework를 사용하여 일대일 형식 관계를 매핑하는 방법에 대해 설명합니다.
1 대 0 또는 1 대 매핑
다시 말하면 다음과 같은 모델을 가지고 있습니다.
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
}
public class Car
{
public int CarId { get; set; }
public string LicensePlate { get; set; }
}
public class MyDemoContext : DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<Car> Cars { get; set; }
}
이제는 다음 사양을 표현할 수 있도록 설정하려고합니다. 한 사람이 자동차를 1 대 또는 0대로 가질 수 있으며 모든 자동차가 한 사람에게 정확히 속합니다 (관계가 양방향이므로 CarA가 PersonA에 속한 경우 PersonA가 소유합니다 'CarA').
그럼 모델을 조금 수정 해보자. 탐색 속성과 외래 키 속성을 추가한다.
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
public int CarId { get; set; }
public virtual Car Car { get; set; }
}
public class Car
{
public int CarId { get; set; }
public string LicensePlate { get; set; }
public int PersonId { get; set; }
public virtual Person Person { get; set; }
}
그리고 구성 :
public class CarEntityTypeConfiguration : EntityTypeConfiguration<Car>
{
public CarEntityTypeConfiguration()
{
this.HasRequired(c => c.Person).WithOptional(p => p.Car);
}
}
이때까지 이것은 자명하다. 자동차에는 필수 자동차 ( HasRequired () )가 있고 선택 자동차를 가지고있는 사람 ( WithOptional () )이 있습니다. 다시 말하지만,이 관계를 구성하는 측면은 중요하지 않습니다. Has / With 및 Required / Optional의 올바른 조합을 사용할 때는주의하십시오. Person
쪽에서 보면 다음과 같이 보일 것입니다.
public class PersonEntityTypeConfiguration : EntityTypeConfiguration<Person>
{
public PersonEntityTypeConfiguration()
{
this.HasOptional(p => p.Car).WithOptional(c => c.Person);
}
}
이제 db 스키마를 살펴 보자.
자세히 보면 People
에게 Car
를 말하는 FK가 없음을 알 수 있습니다. 또한 Car
의 FK는 PersonId
가 아니라 CarId
입니다. 다음은 FK의 실제 스크립트입니다.
ALTER TABLE [dbo].[Cars] WITH CHECK ADD CONSTRAINT [FK_dbo.Cars_dbo.People_CarId] FOREIGN KEY([CarId])
REFERENCES [dbo].[People] ([PersonId])
따라서 우리가 모델에서 가지고있는 CarId
와 PersonId
foregn key 속성은 기본적으로 무시됩니다. 그들은 데이터베이스에 있지만 예상대로 외래 키가 아닙니다. 일대일 매핑이 FK를 EF 모델에 추가하는 것을 지원하지 않기 때문입니다. 그리고 관계형 데이터베이스에서는 일대일 매핑이 문제가 많기 때문입니다.
아이디어는 모든 사람이 정확히 한 대의 자동차를 소유 할 수 있으며 자동차는 그 사람에게만 속할 수 있다는 것입니다. 또는 자동차와 관련된 개인 기록이있을 수 있습니다.
그렇다면 이것을 외래 키로 어떻게 표현할 수 있을까요? 분명한 것은있을 수 PersonId
에서 Car
및 CarId
에서 People
. 모든 사람이 하나의 차를 가질 수 있음을 적용하려면, PersonId
에서 고유해야합니다 Car
. 하지만 PersonId
에 고유 한 People
경우, 다음 방법은 두 개 이상의 레코드를 추가 할 수 PersonId
있다 NULL
(주인이없는 한 차보다 더)? 답변 : SQL Server 2008 이상에서 필터 된 고유 인덱스를 만들 수는 있지만 실제로는 다른 RDBMS는 말할 것도없이이 전문성을 잠시 잊어 버리십시오. 관계의 양쪽 끝을 지정하는 경우는 말할 것도없고 ...
People
및 Car
테이블에 '동일한'기본 키 (연결된 레코드에서 동일한 값)가있는 경우이 규칙을 적용하는 유일한 방법입니다. 이를 위해 Car
CarId
는 People의 PK에 대한 PK 및 FK이어야합니다. 그리고 이것은 전체 스키마를 혼란스럽게 만듭니다. 이것을 사용할 때 Car
PersonId
에서 PK / FK로 이름을 지정하고 적절하게 구성하십시오.
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
public virtual Car Car { get; set; }
}
public class Car
{
public string LicensePlate { get; set; }
public int PersonId { get; set; }
public virtual Person Person { get; set; }
}
public class CarEntityTypeConfiguration : EntityTypeConfiguration<Car>
{
public CarEntityTypeConfiguration()
{
this.HasRequired(c => c.Person).WithOptional(p => p.Car);
this.HasKey(c => c.PersonId);
}
}
이상적은 아니지만 약간 더 좋을 수도 있습니다. 그러나이 솔루션을 사용할 때는 일반적인 명명 규칙을 따르지 않으므로주의해야합니다. 이로 인해 사용자가 잘못 될 수 있습니다. 이 모델에서 생성 된 스키마는 다음과 같습니다.
따라서이 관계는 데이터베이스 스키마에 의해 적용되는 것이 아니라 Entity Framework 자체에 의해 적용됩니다. 그래서 데이터베이스를 직접 사용하지 않으려면이 방법을 사용할 때 매우 조심해야합니다.
일대일 매핑
일대일 매핑 (양면이 필요한 경우) 또한 까다로운 작업입니다.
이것이 외부 키로 어떻게 표현 될 수 있는지 상상해 봅시다. 다시, CarId
에있는 People
을 말한다 CarId
에서 Car
및 PersonId
받는 의미 차에서 PersonId
에 People
.
이제 자동차 기록을 삽입하려면 어떻게됩니까? 이 작업을 성공적으로 수행하려면 PersonId
카 레코드에 지정된 PersonId
가 있어야합니다. 이 PersonId
가 유효하려면 People
의 해당 레코드가 있어야합니다. 좋아, 그럼 사람 레코드를 삽입 해 보자. 그러나 이것이 성공하려면 유효 CarId
가 개인 기록에 있어야합니다. 그러나 그 차는 아직 삽입되지 않았습니다! 먼저 참조 된 사람 레코드를 삽입해야하기 때문에 그렇게 할 수 없습니다. 그러나 참조 된 사람 레코드는 차 레코드를 참조하기 때문에 삽입 할 수 없으므로 먼저 삽입해야합니다 (foreign key-ception :)).
그래서 이것은 '논리적 인'방식으로도 표현 될 수 없습니다. 다시 한 번 외래 키 중 하나를 삭제해야합니다. 어느 것이 당신에게 달려 있습니다. 외래 키가있는 쪽을 '종속'이라고하고, 외래 키가없는 쪽을 '교장'이라고합니다. 그리고 종속물의 고유성을 보장하기 위해 PK는 FK 여야합니다. 따라서 FK 열을 추가하고이를 모델로 가져 오는 것은 지원되지 않습니다.
여기 구성이 있습니다 :
public class CarEntityTypeConfiguration : EntityTypeConfiguration<Car>
{
public CarEntityTypeConfiguration()
{
this.HasRequired(c => c.Person).WithRequiredDependent(p => p.Car);
this.HasKey(c => c.PersonId);
}
}
지금까지는 당신이 정말로 그 논리를 가졌어야했다. 단지 상대방을 선택할 수 있다는 것을 잊지 마라. WithRequired의 Dependent / Principal 버전을 사용하도록주의해야한다. (그리고 여전히 자동차에서 PK를 구성해야한다.)
public class PersonEntityTypeConfiguration : EntityTypeConfiguration<Person>
{
public PersonEntityTypeConfiguration()
{
this.HasRequired(p => p.Car).WithRequiredPrincipal(c => c.Person);
}
}
DB 스키마를 확인하면 일대일 또는 제로 (zero-one) 솔루션의 경우와 정확히 동일하다는 것을 알 수 있습니다. 이것은 스키마에 의해 강제되는 것이 아니라 EF 자체에 의해 시행되기 때문입니다. 다시 한번, 조심하세요 :)
1 또는 0 대 1 또는 0 매핑
끝내려면 양면이 옵션 인 경우를 간략하게 살펴 보겠습니다.
지금까지는이 예제들에 정말 지루함을 느껴야합니다. 그래서 두 가지 FK-s와 잠재적 인 문제를 가지고 세부 사항을 다루지는 않을 것입니다. 스키마하지만 EF 그 자체.
다음은 적용해야하는 설정입니다.
public class CarEntityTypeConfiguration : EntityTypeConfiguration<Car>
{
public CarEntityTypeConfiguration()
{
this.HasOptional(c => c.Person).WithOptionalPrincipal(p => p.Car);
this.HasKey(c => c.PersonId);
}
}
다시, 당신은 다른 쪽에서 구성 할 수 있습니다. 올바른 방법을 사용하도록 조심하십시오. :)