LINQ to Entities 실행 흐름
Entity Framework에 대한 쿼리는 개체 컨텍스트에 대해 실행되는 명령 트리 쿼리로 표현됩니다. LINQ to Entities는 LINQ(Language-Integrated Query) 쿼리를 명령 트리 쿼리로 변환하여 Entity Framework에 대해 실행한 다음 Entity Framework와 LINQ에서 모두 사용할 수 있는 개체를 반환합니다. 다음은 LINQ to Entities 쿼리를 만들고 실행하는 프로세스입니다.
ObjectContext에서 ObjectQuery 인스턴스를 생성합니다.
ObjectQuery 인스턴스를 사용하여 LINQ to Entities 쿼리를 C# 또는 Visual Basic으로 작성합니다.
LINQ 표준 쿼리 연산자 및 식을 명령 트리로 변환합니다.
명령 트리 표현에서 데이터 소스에 대해 쿼리를 실행합니다. 실행 중에 데이터 소스에서 throw되는 모든 예외는 클라이언트에게 직접 전달됩니다.
쿼리 결과를 다시 클라이언트에 반환합니다.
ObjectQuery 인스턴스 생성
ObjectQuery 제네릭 클래스는 0개 이상의 형식화된 엔터티로 구성된 컬렉션을 반환하는 쿼리를 나타냅니다. 개체 쿼리는 수동으로 생성되는 대신 일반적으로 기존 개체 컨텍스트에서 생성되며 항상 해당 개체 컨텍스트에 속합니다. 이 컨텍스트는 쿼리를 작성하고 실행하는 데 필요한 연결 및 메타데이터 정보를 제공합니다. ObjectQuery 제네릭 클래스는 LINQ 쿼리를 증분 빌드할 수 있는 작성기 메서드를 가지고 있는 IQueryable 제네릭 인터페이스를 구현합니다.
쿼리 작성
IQueryable 제네릭 인터페이스를 구현하는 ObjectQuery 제네릭 클래스의 인스턴스는 LINQ to Entities 쿼리의 데이터 소스 역할을 합니다. 쿼리에는 데이터 소스에서 검색하려는 정보를 정확히 지정해야 합니다. 또한 정보를 반환하기 전에 정보를 정렬, 그룹화 및 구체화하는 방법을 쿼리에 지정할 수 있습니다. LINQ에서 쿼리는 변수에 저장됩니다. 이 쿼리 변수는 어떠한 작업을 수행하거나 데이터를 반환하지 않고 쿼리 정보를 저장하기만 합니다. 쿼리를 만든 후에는 해당 쿼리를 실행하여 데이터를 검색해야 합니다.
LINQ to Entities 쿼리는 쿼리 식 구문과 메서드 기반 쿼리 구문이라는 두 가지 구문으로 작성할 수 있습니다. 쿼리 식 구문과 메서드 기반 쿼리 구문은 C# 3.0과 Visual Basic 9.0의 새로운 기능입니다.
자세한 내용은 LINQ to Entities의 쿼리를 참조하십시오.
다음 쿼리 식 구문 예제에서는 AdventureWorks 개체 컨텍스트에서 ObjectQuery 인스턴스를 생성한 다음 Select를 사용하여 Product의 모든 행을 반환합니다.
Using AWEntities As New AdventureWorksEntities
Dim products As ObjectQuery(Of Product) = AWEntities.Product
Dim productNames = _
From p In products _
Select p
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
ObjectQuery<Product> products = AWEntities.Product;
IQueryable<Product> productNames =
from p in products
select p;
}
다음 메서드 기반 쿼리 구문 예제에서는 AdventureWorks 개체 컨텍스트에서 ObjectQuery 인스턴스를 생성한 다음 Select를 사용하여 Product의 모든 행을 반환합니다.
Using AWEntities As New AdventureWorksEntities
Dim productNames = AWEntities.Product.Select(Function(p) p.Name)
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
ObjectQuery<Product> products = AWEntities.Product;
IQueryable<Product> productNames = products.Select(p => p);
}
쿼리 변환
LINQ to Entities 쿼리를 Entity Framework에 대해 실행하려면 LINQ 쿼리를 Entity Framework에 대해 실행할 수 있는 명령 트리 표현으로 변환해야 합니다.
LINQ to Entities 쿼리는 LINQ 표준 쿼리 연산자(예: Select, Where 및 GroupBy)와 식(x > 10, Contact.LastName 등)으로 구성됩니다. LINQ 연산자는 클래스로 정의되지 않으며 클래스에 있는 메서드입니다. LINQ에서 식은 System.Linq.Expressions 네임스페이스 내의 형식에 허용되는 모든 항목을 포함할 수 있습니다. 확대하면 람다 함수로 표현할 수 있는 모든 항목을 포함할 수 있습니다. LINQ의 식은 ObjectQuery에서 지원되고 정의에 따라 데이터베이스에서 허용되는 연산으로 제한된 Entity Framework에서 허용되는 식의 상위 집합입니다.
Entity Framework에서는 연산자와 식이 모두 단일 형식 계층 구조로 표현된 다음 명령 트리에 배치됩니다. 명령 트리는 Entity Framework에서 쿼리를 실행하는 데 사용됩니다. LINQ 쿼리를 명령 트리로 표현할 수 없는 경우에는 쿼리를 변환할 때 예외가 throw됩니다. LINQ to Entities 쿼리 변환에는 표준 쿼리 연산자 변환과 식 변환이라는 두 가지 하위 변환이 있습니다.
많은 LINQ 표준 쿼리 연산자가 LINQ to Entities에서 올바르게 변환되지 않습니다. 이러한 연산자를 사용하면 쿼리를 변환할 때 예외가 발생합니다. 지원되는 LINQ to Entities 연산자 목록을 보려면 지원되는 메서드 및 지원되지 않는 메서드(LINQ to Entities)를 참조하십시오.
LINQ to Entities의 표준 쿼리 연산자를 사용하는 방법에 대한 자세한 내용은 LINQ to Entities 쿼리의 표준 쿼리 연산자를 참조하십시오.
일반적으로 LINQ to Entities의 식은 서버에서 계산되므로 식의 동작은 CLR 의미 체계를 따르지 않습니다. 자세한 내용은 LINQ to Entities 쿼리의 식을 참조하십시오.
쿼리 실행
사용자가 만든 LINQ 쿼리는 Entity Framework와 호환되는 표현(명령 트리 형태)으로 변환된 다음 데이터 소스에 대해 실행됩니다. 쿼리 실행 시 모든 쿼리 식(또는 쿼리의 구성 요소)은 클라이언트나 서버에서 계산됩니다. 이러한 식에는 결과 구체화나 엔터티 프로젝션에 사용되는 식이 포함됩니다.
쿼리 식이 실행되는 시점은 다양할 수 있습니다. LINQ 쿼리는 쿼리 변수가 만들어질 때 실행되지 않고 쿼리 변수가 반복될 때마다 실행됩니다. 이러한 실행을 지연된 실행이라고 합니다. 쿼리를 즉시 실행할 수도 있습니다. 이 방법은 쿼리 결과를 캐시하는 데 유용합니다. 다음 예제에서는 Select를 사용하여 Product 테이블의 모든 행을 반환하고 제품 이름을 표시합니다. foreach/For Each 루프의 쿼리 변수를 반복하면 쿼리가 실행됩니다.
Using AWEntities As New AdventureWorksEntities
Dim products As ObjectQuery(Of Product) = AWEntities.Product
Dim productNames = _
From p In products _
Select p.Name
Console.WriteLine("Product Names:")
For Each productName In productNames
Console.WriteLine(productName)
Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
ObjectQuery<Product> products = AWEntities.Product;
IQueryable<string> productNames =
from p in products
select p.Name;
Console.WriteLine("Product Names:");
foreach (var productName in productNames)
{
Console.WriteLine(productName);
}
}
LINQ to Entities 쿼리를 실행하면 쿼리의 일부 식은 서버에서 실행되고 일부 식은 클라이언트에서 로컬로 실행될 수 있습니다. 식에 대한 클라이언트 쪽 계산은 쿼리가 서버에서 실행되기 전에 수행됩니다. 식이 클라이언트에서 계산되면 계산 결과로 쿼리의 식이 대체된 다음 서버에서 쿼리가 실행됩니다. 쿼리가 데이터 소스에서 실행되므로 데이터 소스 구성이 클라이언트에 지정된 동작을 재정의합니다. Null 값 처리 및 숫자의 전체 자릿수가 이에 대한 예입니다. 서버에서 쿼리를 실행하는 중에 throw되는 모든 예외는 클라이언트에 직접 전달됩니다. 자세한 내용은 쿼리 실행을 참조하십시오.
구체화
구체화는 쿼리 결과를 CLR 형식으로 클라이언트에게 다시 반환하는 프로세스입니다. LINQ to Entities에서는 쿼리 결과 데이터 레코드가 반환되지 않으며 사용자나 Entity Framework에 의해 정의되었거나 컴파일러에 의해 생성된(익명 형식) 백업 CLR 형식이 항상 사용됩니다. 모든 개체 구체화는 Entity Framework에 의해 수행됩니다. Entity Framework와 CLR 간의 매핑 실패로 인해 오류가 발생하면 개체 구체화 동안 예외가 throw됩니다.
쿼리 결과는 대개 다음 중 하나로 반환됩니다.
EDM에 있는 0개 이상의 형식화된 엔터티 개체로 구성된 컬렉션 또는 복합 형식의 프로젝션
EDM에서 지원되는 CLR 형식
인라인 컬렉션
익명 형식
자세한 내용은 쿼리 결과를 참조하십시오.