코드 우선 : 독립 연결 vs. 외래 키 연결?


102

새로운 프로젝트를 시작하고 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. 없는 경우 외래 키 연결을 사용하는 이유는 무엇입니까?

답변:


106

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를 할당해야합니다.
  • 이 연관은 맵핑되지 않고 대신 참조 제한 조건을 정의합니다.

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

편집하다:

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


매우 통찰력있는 답변과 올바른 용어에 대한 헤드 업에 감사드립니다. 두 기술의 장단점과 주제에 대한 많은 리소스를 찾는 데 도움이되었습니다.
Daniel Liuzzi 2011 년

1
방금 당신의 기사를 보았습니다, Ladislav. 이 두 접근 방식의 차이점을 더 잘 이해할 수있는 매우 흥미로운 읽기와 훌륭한 리소스입니다. 건배.
Daniel Liuzzi 2011 년

1
@GaussZ : 내가 아는 것처럼 EF4 (FK 연관이 도입 된 곳) 이후로 연관이 처리되는 방식에는 변화가 없었습니다.
Ladislav Mrnka 2013

1
이것과 다른 답변은 성능 문제에 영향을 미치지 않는 것 같습니다. 그러나 MSDN 기사의 섹션 2.2 뷰 생성 성능에 영향을 미치는 요인 에 따르면 독립 연결을 사용하면 외래 키 연결보다보기 생성 비용이 증가하는 것으로 보입니다.
Veverke

1
@LadislavMrnka : 위에서 언급 한 기사에 대한 링크가 작동하는지 다시 확인할 수 있습니까? 액세스 할 수 없습니다.
Veverke

34

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

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

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


5
동의합니다. 이것이 Ladislav가 제안한 것처럼 내가 한 일입니다. 두 세계의 장점을 모두 제공합니다. 모든 속성이 필요할 때 전체 개체, PK 만 필요하고 나머지는 신경 쓰지 않을 때의 ID입니다.
Daniel Liuzzi

9

독립적 인 연관 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);

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


2
이것은 좋은 결과입니다. 그러나 주문에 고객을 연결하는 해결 방법 (올바른 방법이라고 생각)은 다음과 같이 db 컨텍스트에서로드하는 것입니다. var order = new Order { Id = 1, Customer = db.Customers.Find(1) }; 또는 Select 메서드를 사용하여 db 컨텍스트에서 고객을로드 할 수 있습니다. 이것은 독립적 인 협회와 함께 작동합니다.
tala9999

4

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.