[entity-framework] 코드 우선 : 독립 연결 vs. 외래 키 연결?

새로운 프로젝트를 시작하고 POCO를 디자인 할 때마다 나 자신과 정신적 인 토론을합니다. 외래 키 연결 을 선호하는 것으로 보이는 많은 자습서 / 코드 샘플을 보았습니다 .

외래 키 연결

public class Order
{
    public int ID { get; set; }
    public int CustomerID { get; set; } // <-- Customer ID
    ...
}

독립적 인 협회와는 반대로 :

독립 협회

public class Order
{
    public int ID { get; set; }
    public Customer Customer { get; set; } // <-- Customer object
    ...
}

나는 과거에 NHibernate와 함께 일했고, 더 많은 OO를 느낄뿐만 아니라 (지연 로딩과 함께) 자신의 ID가 아닌 전체 Customer 객체에 대한 액세스를 제공하는 이점이있는 독립적 인 연결을 사용했습니다. 이를 통해 예를 들어 Order 인스턴스를 검색 한 다음 Order.Customer.FirstName명시 적으로 조인 하지 않고도 수행 할 수 있습니다. 이는 매우 편리합니다.

요약하자면 내 질문은 다음과 같습니다.

  1. 독립적 인 연결을 사용하는 데 큰 단점이 있습니까? 과…
  2. 없는 경우 외래 키 연결을 사용하는 이유는 무엇입니까?


답변

ORM을 최대한 활용하려면 엔티티 참조를 사용해야합니다.

public class Order
{
    public int ID { get; set; }
    public Customer Customer { get; set; } // <-- Customer object
    ...
}

FK가있는 데이터베이스에서 엔티티 모델을 생성하면 항상 엔티티 참조가 생성됩니다. 이를 사용하지 않으려면 EDMX 파일을 수동으로 수정하고 FK를 나타내는 속성을 추가해야합니다. 적어도 이것은 독립 연결 만 허용 된 Entity Framework v1의 경우였습니다.

Entity Framework v4는 외래 키 연결이라는 새로운 유형의 연결을 제공합니다. 독립 키와 외래 키 연결의 가장 분명한 차이점은 Order 클래스입니다.

public class Order
{
    public int ID { get; set; }
    public int CustomerId { get; set; }  // <-- Customer ID
    public Customer Customer { get; set; } // <-- Customer object
    ...
}

보시다시피 FK 속성과 엔티티 참조가 모두 있습니다. 두 가지 유형의 연결 간에는 더 많은 차이점이 있습니다.

독립 협회

  • 에서 별도의 개체로 표시됩니다 ObjectStateManager. 그것은 자체가 있습니다 EntityState!
  • 연합을 구축 할 때 항상 연합의 양쪽 끝에서 엔티티가 필요합니다.
  • 이 연관은 엔티티와 동일한 방식으로 매핑됩니다.

외래 키 연결

  • 에서 별도의 개체로 표시되지 않습니다 ObjectStateManager. 따라서 몇 가지 특별한 규칙을 따라야합니다.
  • 협회를 구축 할 때 양쪽 끝이 필요하지 않습니다. 하위 항목과 상위 항목의 PK가 있으면 충분하지만 PK 값은 고유해야합니다. 따라서 외래 키 연결을 사용할 때 관계에 사용되는 새로 생성 된 엔터티에도 임시 고유 ID를 할당해야합니다.
  • 이 연관은 맵핑되지 않고 대신 참조 제한 조건을 정의합니다.

외래 키 연결을 사용하려면 엔터티 데이터 모델 마법사 의 모델외래 키 열 포함 을 선택해야합니다 .

편집하다:

이 두 유형의 연관성 간의 차이점은 잘 알려져 있지 않아 이에 대한 자세한 내용과 내 의견을 담은 짧은 기사작성했습니다 .


답변

둘 다 사용하십시오. 엔터티 참조를 가상으로 만들어 지연로드를 허용합니다. 이렇게 :

public class Order
{
  public int ID { get; set; }
  public int CustomerID { get; set; }
  public virtual Customer Customer { get; set; } // <-- Customer object
  ...
}

이를 통해 불필요한 DB 조회를 줄이고 지연 로딩을 허용하며 원하는 ID를 알고 있으면 쉽게 확인 / 설정할 수 있습니다. 둘 다 사용한다고해서 테이블 구조가 변경되는 것은 아닙니다.


답변

독립적 인 연관 AddOrUpdate은 일반적으로 Seed방법 에서 사용되는 것과 잘 작동하지 않습니다 . 참조가 기존 항목 인 경우 다시 삽입됩니다.

// Existing customer.
var customer = new Customer { Id = 1, Name = "edit name" };
db.Set<Customer>().AddOrUpdate(customer);

// New order.
var order = new Order { Id = 1, Customer = customer };
db.Set<Order>().AddOrUpdate(order);

그 결과 기존 고객이 다시 삽입되고 새 (다시 삽입 된) 고객이 새 주문과 연결됩니다.


외래 키 연결을 사용하고 ID를 할당하지 않는 한.

 // Existing customer.
var customer = new Customer { Id = 1, Name = "edit name" };
db.Set<Customer>().AddOrUpdate(customer);

// New order.
var order = new Order { Id = 1, CustomerId = customer.Id };
db.Set<Order>().AddOrUpdate(order);

우리는 예상되는 동작을 가지고 있으며 기존 고객은 새로운 주문과 연결됩니다.


답변

불필요한 조회를 피하기 위해 객체 접근 방식을 선호합니다. 속성 객체는 팩토리 메서드를 호출하여 전체 항목을 빌드 할 때처럼 쉽게 채울 수 있습니다 (중첩 된 항목에 대한 간단한 콜백 코드 사용). 메모리 사용량을 제외하고는 볼 수있는 단점이 없습니다 (하지만 개체를 ​​캐시 할 수 있습니까?). 따라서 수행중인 모든 작업은 스택을 힙으로 대체하고 조회를 수행하지 않아 성능을 향상시키는 것입니다. 이해가 되길 바랍니다.


답변