관련 개체 로드(Entity Framework)
이 항목에서는 관련 엔터티를 로드하는 데 사용할 수 있는 패턴에 대해 설명합니다. 엔터티 형식은 데이터 모델의 연결을 나타내는 탐색 속성을 정의할 수 있습니다. 이러한 속성을 사용하여 정의된 연결에 의해 반환된 엔터티와 관련된 엔터티를 로드할 수 있습니다. 데이터 모델을 기반으로 엔터티가 생성되면 연결의 양쪽 End에서 엔터티의 탐색 속성이 생성됩니다. 이러한 탐색 속성은 일대일 또는 다대일 관계의 "일(one)" 쪽에서 참조를 반환하거나 일대다 또는 다대다 관계의 "다(many)" 쪽에서 컬렉션을 반환합니다. 자세한 내용은 탐색 속성 및 관계 정의 및 관리(Entity Framework)를 참조하십시오.
다음 패턴에서는 관련 엔터티를 로드하는 방법에 대해 설명합니다.
로드 패턴 | 설명 |
---|---|
쿼리에 지정됨 |
이러한 관계를 탐색 속성을 통해 명시적으로 탐색하는 Entity SQL 또는 LINQ to Entities 쿼리를 작성할 수 있습니다. 이러한 쿼리를 실행하면 쿼리의 가장 바깥쪽 프로젝션에 탐색 속성으로 포함된 관련 엔터티가 반환됩니다. 자세한 내용은 다음을 참조하십시오. |
명시적 로드 |
엔터티를 ObjectContext에 명시적으로 로드하려면 데이터베이스를 대상으로 한 라운드트립이 여러 번 필요하며 MARS(Multiple Active Result Set)가 요구될 수도 있지만, 반환되는 데이터의 양은 로드되는 엔터티로 제한됩니다. EntityCollection 또는 EntityReference의 Load 메서드나 ObjectContext의 LoadProperty 메서드를 사용하여 데이터 소스에서 관련 엔터티를 명시적으로 검색할 수 있습니다. Load 메서드를 호출할 때마다 데이터베이스에 대한 연결이 열려 관련 정보를 검색합니다. 이제 관련 엔터티를 명시적으로 요청하지 않으면 쿼리가 실행되지 않습니다. 명시적 로드는 Entity Framework 의 기본 동작입니다.
참고:
Load가 호출되기 전에 관련 엔터티에 대한 적은 양의 정보가 이미 ObjectContext에 로드됩니다.
자세한 내용은 이 항목의 Explicitly Loading Related Objects 단원을 참조하십시오. |
지연 로드 |
이러한 형식의 로드에서는 탐색 속성에 액세스하면 데이터 소스에서 관련 엔터티가 자동으로 로드됩니다. 또한 엔터티가 ObjectContext에 없는 경우 액세스하는 각 탐색 속성은 데이터 소스에 대해 쿼리를 별도로 실행할 수 있습니다. 자세한 내용은 이 항목의 Lazy Loading 단원을 참조하십시오. |
즉시 로드 또는 Include를 사용하여 쿼리 경로 정의 |
응용 프로그램에서 필요한 관련 엔터티 그래프의 정확한 모양을 알고 있는 경우 ObjectQuery의 Include 메서드를 사용하여 초기 쿼리의 일부로 반환할 관련 엔터티를 제어하는 쿼리 경로를 정의할 수 있습니다. 쿼리 경로를 정의하는 경우 경로로 정의된 모든 엔터티를 단일 결과 집합으로 반환하려면 데이터베이스에 대한 단일 요청만 필요하며 경로에 지정된 형식의 모든 관련 엔터티가 쿼리에서 반환하는 각 개체와 함께 로드됩니다. 자세한 내용은 이 항목의 Defining a Query Path to Shape Query Results 단원을 참조하십시오. |
명시적으로 관련 엔터티 개체 로드
관련 엔터티를 명시적으로 로드하려면 탐색 속성을 통해 반환된 관련 End에서 Load 메서드를 호출해야 합니다. 일대다 관계의 경우 EntityCollection의 Load 메서드를 호출하고, 일대일 관계의 경우 EntityReference의 Load 메서드를 호출합니다. POCO 엔터티로 작업하는 경우 ObjectContext의 LoadProperty 메서드를 사용합니다. 자세한 내용은 관련 POCO 엔터티 로드(Entity Framework)를 참조하십시오. LoadProperty 메서드는 EntityObject에서 파생된 엔터티와 함께 사용할 수도 있습니다. 이러한 메서드는 관련 개체 데이터를 개체 컨텍스트에 로드합니다. 쿼리에서 결과가 반환되면 foreach 루프(Visual Basic에서는 For Each...Next)를 사용하여 개체 컬렉션을 열거하고 결과의 각 엔터티에 대한 EntityReference 및 EntityCollection 속성에서 조건에 따라 Load 메서드를 호출할 수 있습니다.
참고: |
---|
foreach(C#) 또는 For Each(Visual Basic) 열거를 수행하는 동안 Load 메서드를 호출하면 Entity Framework 에서는 새 데이터 판독기를 열려고 시도합니다.연결 문자열에서 multipleactiveresultsets=true를 지정하여 MARS(Multiple Active Result Set)를 활성화하지 않은 경우에는 이 작업이 실패합니다.자세한 내용은 MSDN에서 MARS(Multiple Active Result Sets) 사용을 참조하십시오.쿼리 결과를 List 컬렉션에 로드할 수도 있으며, 이렇게 하면 데이터 판독기가 닫히고 컬렉션 전체를 열거하여 참조된 엔터티를 로드할 수 있게 됩니다. |
자세한 내용은 방법: 명시적으로 관련 개체 로드(Entity Framework)를 참조하십시오.
쿼리 경로를 정의하여 쿼리 결과 셰이핑
쿼리 경로를 지정하려면 문자열로 나타낸 개체 그래프를 ObjectQuery의 Include 메서드에 전달합니다. 이 경로는 개체 쿼리를 실행하면 반환될 관련 엔터티를 지정합니다. 예를 들어, Contact 개체에 대한 쿼리에서 쿼리 경로를 정의하면 개별 관련 SalesOrderHeader와 SalesOrderDetail이 반환됩니다. 다음 쿼리에서 이를 확인할 수 있습니다.
' Define a LINQ query with a path that returns
' orders and items for a contact.
Dim contacts = (From contact In context.Contacts.Include("SalesOrderHeaders.SalesOrderDetails") _
Select contact).FirstOrDefault()
// Define a LINQ query with a path that returns
// orders and items for a contact.
var contacts = (from contact in context.Contacts
.Include("SalesOrderHeaders.SalesOrderDetails")
select contact).FirstOrDefault();
쿼리 경로를 정의할 때는 다음 사항을 고려해야 합니다.
쿼리 경로는 쿼리 작성기 메서드 및 LINQ 쿼리에 사용할 수 있습니다.
Include를 호출하는 경우 쿼리 경로는 ObjectQuery의 반환된 인스턴스에만 사용할 수 있습니다. ObjectQuery의 다른 인스턴스와 개체 컨텍스트 자체에는 영향을 주지 않습니다.
Include는 쿼리 개체를 반환하므로 이 메서드를 ObjectQuery에 대해 여러 번 호출하여 여러 관계의 엔터티를 포함할 수 있습니다. 예를 들면 다음과 같습니다.
' Create a SalesOrderHeader query with two query paths, ' one that returns order items and a second that returns the ' billing and shipping addresses for each order. Dim query As ObjectQuery(Of SalesOrderHeader) = context.SalesOrderHeaders.Include("SalesOrderDetails").Include("Address")
// Create a SalesOrderHeader query with two query paths, // one that returns order items and a second that returns the // billing and shipping addresses for each order. ObjectQuery<SalesOrderHeader> query = context.SalesOrderHeaders.Include("SalesOrderDetails").Include("Address");
쿼리 경로를 사용하면 단순 개체 쿼리의 데이터 소스에 대해 복잡한 명령이 실행될 수 있습니다. 이는 단일 쿼리에서 관련 개체를 반환하는 데 하나 이상의 조인이 필요하기 때문이며, 이 경우 데이터 소스에서 각 관련 엔터티에 대한 중복 데이터가 발생합니다. 이런 복잡성은 다대다 관계가 포함된 상속이나 경로를 가진 엔터티와 같은 복합 모델에 대한 쿼리에서 더 커집니다. ObjectQuery에서 생성되는 명령을 보려면 ToTraceString 메서드를 사용하십시오. 쿼리 경로에 관련 개체가 너무 많거나 개체에 행 데이터가 너무 많은 경우, 데이터 소스에서 쿼리 처리가 완료되지 못할 수 있습니다. 쿼리에 필요한 중간 임시 저장소가 데이터 소스의 용량을 초과하는 경우 이런 현상이 발생할 수 있습니다. 이 경우 관련 개체를 명시적으로 로드하거나 지연된 로드를 사용하여 데이터 소스 쿼리의 복잡성을 줄일 수 있습니다. 복합 쿼리를 최적화한 후에도 시간 초과가 빈번히 발생하는 경우 CommandTimeout 속성을 설정하여 시간 제한 값을 늘리는 것이 좋습니다.
자세한 내용은 방법: 쿼리 경로를 사용하여 결과 셰이핑(Entity Framework)을 참조하십시오.
엔터티 개체 지연 로드
Entity Framework 에서는 관련 엔터티의 지연 로드를 지원합니다. Entity Framework 런타임에서 ObjectContext 인스턴스에 있는 LazyLoadingEnabled 속성의 기본값은 false입니다. 그러나 Entity Framework 도구를 사용하여 새 모델 및 생성된 해당 클래스를 만드는 경우에는 개체 컨텍스트의 생성자에서 LazyLoadingEnabled가 true로 설정됩니다. 지연 로드를 사용할 경우 관련 엔터티는 탐색 속성의 get 접근자에서 프로그래밍 방식으로 액세스하기 전까지는 데이터 소스에서 로드되지 않습니다. 지연 로드를 사용하지 않으려면 System.Data.Objects.ObjectContext.ContextOptions 속성에서 반환된 ObjectContextOptions 인스턴스에서 LazyLoadingEnabled 속성을 false로 설정합니다.
지연 로드는 즉시 로드와 함께 사용할 수 있습니다. 이러한 방식으로 기본 데이터 그래프는 쿼리 경로를 사용하여 정의할 수 있으며, 원래 쿼리 경로에 포함되지 않은 추가 관련 엔터티는 필요한 경우에 로드할 수 있습니다. 자세한 내용은 방법: 지연 로드를 사용하여 관련 개체 로드(Entity Framework)를 참조하십시오.
다음은 지연 로드를 사용할 때 고려해야 할 사항입니다.
지연 로드는 단일 엔터티(예: EntityReference)와 엔터티 컬렉션(예: EntityCollection)을 모두 반환하는 탐색 속성에 대해 지원됩니다.
지연 로드가 사용되고 관련 엔터티가 이미 로드된 경우 관련 엔터티는 다시 로드되지 않습니다.
지연 로드는 Detached 상태의 엔터티에 대해 지원됩니다. 이 경우 Detached 상태의 관련 개체도 반환됩니다.
지연 로드 동작은 엔터티가 NoTracking MergeOption과 함께 로드된 경우에도 데이터 소스에서 개체를 검색하는 데 사용되거나 개체가 추가 또는 연결된 ObjectContext 인스턴스에 의해 결정됩니다. 이로 인해 이 컨텍스트가 삭제된 경우에는 지연 로드 동작을 변경할 수 없으며 모든 추가 지연 로드 작업이 실패합니다.
엔터티를 serialize할 때에는 지연 로드를 사용하지 마십시오. 이렇게 하지 않으면 지연 로드가 트리거되고 serialize된 엔터티에 예상한 것보다 많은 데이터가 포함될 수 있습니다.
지연 로드를 POCO 엔터티와 함께 사용하는 경우 추가로 고려할 사항이 있습니다. 자세한 내용은 관련 POCO 엔터티 로드(Entity Framework)를 참조하십시오.
관련 엔터티 개체 쿼리
EntityCollection에서 CreateSourceQuery 메서드를 호출하면 먼저 개체를 컬렉션에 로드하지 않고도 관련 개체를 쿼리할 수 있습니다. CreateSourceQuery는 실행 시 Load 메서드를 호출할 때와 동일한 개체 집합을 반환하는 ObjectQuery를 반환합니다. 쿼리 작성기 메서드를 이 개체 쿼리에 적용하여 컬렉션에 로드된 개체를 추가로 필터링할 수 있습니다. 자세한 내용은 방법: EntityCollection의 관련 개체 쿼리(Entity Framework)를 참조하십시오.
ObjectQuery는 엔터티 데이터를 엔터티로 반환합니다. 그러나 가장 바깥쪽 쿼리 프로젝션에 탐색 속성이 포함되어 있으면 쿼리는 탐색에서 액세스되는 관련 엔터티도 반환합니다. 자세한 내용은 방법: 탐색 속성을 사용하여 관계 탐색(Entity Framework)을 참조하십시오.
성능 고려 사항
관련 엔터티 로드 패턴을 선택할 때 데이터 소스에 대한 연결 수 및 타이밍과 단일 쿼리를 사용하여 반환된 데이터 양 및 이러한 사용 방법의 복잡성을 서로 비교하여 각 접근 방식의 동작을 고려하십시오. 즉시 로드는 단일 쿼리에서 쿼리된 엔터티와 모든 관련 엔터티를 함께 반환합니다. 즉, 데이터 소스에 대한 연결이 하나만 있지만 초기 쿼리에서 많은 양의 데이터가 반환됩니다. 또한 데이터 소스에 대해 실행된 쿼리에 필요한 추가 조인 때문에 쿼리 경로는 보다 복잡한 쿼리를 생성합니다.
명시적 및 지연된 로드를 통해 관련 개체 데이터가 실제로 필요할 때까지 해당 데이터에 대한 요청을 연기할 수 있습니다. 이렇게 하면 총 개수보다 더 적은 데이터를 반환하는 덜 복잡한 초기 쿼리가 생성됩니다. 그러나 관련 개체를 연속적으로 로드할 때마다 데이터 소스에 대한 연결이 생성되고 쿼리가 실행됩니다. 지연 로드의 경우 이러한 연결은 탐색 속성에 액세스하고 관련 엔터티가 로드되지 않으면 발생합니다. 초기 쿼리에 의해 반환되는 관련 엔터티를 확인하거나 데이터 소스에서 관련 엔터티가 로드되는 타이밍을 관리하려면 지연 로드를 사용하지 않도록 설정해야 합니다. 지연 로드는 Entity Framework 에서 생성된 개체 컨텍스트의 생성자에서 설정됩니다.
자세한 내용은 성능 고려 사항(Entity Framework)을 참조하십시오.
참고 항목
개념
개념적 모델 쿼리(Entity Framework)
개체 쿼리(Entity Framework)
쿼리 작성기 메서드(Entity Framework)