데이터 서비스 쿼리(WCF Data Services)

WCF Data Services 클라이언트 라이브러리를 사용하면 LINQ(Language-Integrated Query) 사용을 비롯한 익숙한 .NET Framework 프로그래밍 패턴을 사용하여 데이터 서비스에 대해 쿼리를 실행할 수 있습니다. 클라이언트 라이브러리는 클라이언트에서 DataServiceQuery 클래스의 인스턴스로 정의된 쿼리를 HTTP GET 요청 메시지로 변환합니다. 라이브러리는 응답 메시지를 받아 클라이언트 데이터 서비스 클래스의 인스턴스로 변환합니다. 이러한 클래스는 DataServiceQuery가 속해 있는 DataServiceContext에 의해 추적됩니다.

데이터 서비스 쿼리

DataServiceQuery 제네릭 클래스는 0개 이상의 엔터티 형식 인스턴스의 컬렉션을 반환하는 쿼리를 나타냅니다. 데이터 서비스 쿼리는 항상 기존 데이터 서비스 컨텍스트에 속합니다. 이 컨텍스트는 쿼리를 작성하고 실행하는 데 필요한 서비스 URI 및 메타데이터 정보를 유지 관리합니다.

서비스 참조 추가 대화 상자를 사용하여 데이터 서비스를 .NET Framework 기반 클라이언트 응용 프로그램에 추가하면 DataServiceContext 클래스에서 상속하는 엔터티 컨테이너 클래스가 만들어집니다. 이 클래스에는 형식화된 DataServiceQuery 인스턴스를 반환하는 속성이 포함됩니다. 데이터 서비스에서 노출하는 엔터티 집합마다 속성이 하나씩 있습니다. 이러한 속성을 사용하면 형식화된 DataServiceQuery 인스턴스를 보다 쉽게 만들 수 있습니다.

쿼리는 다음 시나리오에서 실행됩니다.

  • 결과가 다음과 같이 암시적으로 열거되는 경우

    • foreach(C#) 또는 For Each(Visual Basic) 루프 중과 같이 엔터티 집합을 나타내는 DataServiceContext에 대한 속성이 열거되는 경우

    • 쿼리가 List 컬렉션에 할당된 경우

  • Execute 또는 BeginExecute 메서드를 명시적으로 호출한 경우

  • First, Single 등의 LINQ 쿼리 실행 연산자를 호출한 경우

다음 쿼리를 실행하면 Northwind 데이터 서비스에 있는 모든 Customers 엔터티가 반환됩니다.

' Define a new query for Customers.
Dim query As DataServiceQuery(Of Customer) = context.Customers
// Define a new query for Customers.
DataServiceQuery<Customer> query = context.Customers;

자세한 내용은 방법: 데이터 서비스 쿼리 실행(WCF Data Services)을 참조하십시오.

WCF Data Services 클라이언트는 C#에서 동적 유형을 사용하는 경우와 같이 런타임에 바인딩된 개체에 대한 쿼리를 지원합니다. 하지만 성능상의 이유로 데이터 서비스에 대해 항상 강력한 형식의 쿼리를 작성해야 합니다. Tuple 유형 및 동적 개체는 클라이언트에서 지원되지 않습니다.

LINQ 쿼리

DataServiceQuery 클래스가 LINQ로 정의된 IQueryable 인터페이스를 구현하기 때문에 WCF Data Services 클라이언트 라이브러리는 엔터티 집합 데이터에 대한 LINQ 쿼리를 데이터 서비스 리소스에 대해 평가되는 쿼리 식을 나타내는 URI로 변환할 수 있습니다. 다음 예제는 운송료가 $30를 초과하는 Orders를 반환하고 결과를 운송료순으로 정렬하는 이전 DataServiceQuery와 동일한 LINQ 쿼리입니다.

Dim selectedOrders = From o In context.Orders _
        Where (o.Freight > 30) _
        Order By o.ShippedDate Descending _
        Select o
var selectedOrders = from o in context.Orders
                     where o.Freight > 30
                     orderby o.ShippedDate descending 
                     select o;

이 LINQ 쿼리는 Northwind 기반 퀵 스타트 데이터 서비스에 대해 실행되는 다음 쿼리 URI로 변환됩니다.

https://localhost:12345/Northwind.svc/Orders?Orderby=ShippedDate&?filter=Freight gt 30
Dd673933.note(ko-kr,VS.100).gif참고:
LINQ 구문으로 표현할 수 있는 쿼리 집합은 데이터 서비스에 사용되는 REST(Representational State Transfer) 기반 URI 구문에서 사용할 수 있는 것보다 광범위합니다. 쿼리를 대상 데이터 서비스의 URI에 매핑할 수 없으면 NotSupportedException이 발생합니다.

자세한 내용은 LINQ 고려 사항(WCF Data Services)을 참조하십시오.

쿼리 옵션 추가

데이터 서비스 쿼리는 WCF Data Services 에서 제공하는 모든 쿼리 옵션을 지원합니다. AddQueryOption 메서드를 호출하여 DataServiceQuery 인스턴스에 쿼리 옵션을 추가합니다. AddQueryOption은 원래 쿼리와 동일하지만 새로운 쿼리 옵션이 설정된 새 DataServiceQuery 인스턴스를 반환합니다. 다음 쿼리를 실행하면 Freight 값으로 필터링되고 OrderID를 기준으로 내림차순으로 정렬된 Orders가 반환됩니다.

' Define a query for orders with a Freight value greater than 30
' and that is ordered by the ship date, descending.
Dim selectedOrders As DataServiceQuery(Of Order) = context.Orders _
.AddQueryOption("$filter", "Freight gt 30") _
.AddQueryOption("$orderby", "OrderID desc")
// Define a query for orders with a Freight value greater than 30
// and that is ordered by the ship date, descending.
DataServiceQuery<Order> selectedOrders = context.Orders
    .AddQueryOption("$filter", "Freight gt 30")
    .AddQueryOption("$orderby", "OrderID desc");

$orderby 쿼리 옵션을 사용하여 단일 속성에 따라 쿼리를 정렬하고 필터링할 수 있습니다. 다음 예제에서는 반환된 Orders 개체를 Freight 속성의 값에 따라 필터링하고 정렬합니다.

' Create the DataServiceContext using the service URI.
Dim context = New NorthwindEntities(svcUri)

' Define a query for orders with a Freight value greater than 30
' that also orders the result by the Freight value, descending.
Dim selectedOrders As DataServiceQuery(Of Order) = _
context.Orders.AddQueryOption("$orderby", "Freight gt 30 desc")

Try
    ' Enumerate over the results of the query.
    For Each order As Order In selectedOrders
        Console.WriteLine("Order ID: {0} - Freight: {1}", _
                order.OrderID, order.Freight)
    Next
Catch ex As DataServiceQueryException
    Throw New ApplicationException( _
            "An error occurred during query execution.", ex)
End Try
// Create the DataServiceContext using the service URI.
NorthwindEntities context = new NorthwindEntities(svcUri);

// Define a query for orders with a Freight value greater than 30
// that also orders the result by the Freight value, descending.
DataServiceQuery<Order> selectedOrders = context.Orders
    .AddQueryOption("$orderby", "Freight gt 30 desc");

try
{
    // Enumerate over the results of the query.
    foreach (Order order in selectedOrders)
    {
        Console.WriteLine("Order ID: {0} - Freight: {1}",
            order.OrderID, order.Freight);
    }
}
catch (DataServiceQueryException ex)
{
    throw new ApplicationException(
        "An error occurred during query execution.", ex);
}

AddQueryOption 메서드를 연속적으로 호출하여 복잡한 쿼리 식을 생성할 수 있습니다. 자세한 내용은 방법: 데이터 서비스 쿼리에 쿼리 옵션 추가(WCF Data Services)를 참조하십시오.

쿼리 옵션을 통해 LINQ 쿼리의 구문 구성 요소를 표현할 수도 있습니다. 자세한 내용은 LINQ 고려 사항(WCF Data Services)을 참조하십시오.

Dd673933.note(ko-kr,VS.100).gif참고:
$select 쿼리 옵션은 AddQueryOption 메서드를 사용하여 쿼리 URI에 추가할 수 없습니다. LINQ Select 메서드를 사용하여 클라이언트에서 요청 URI에 $select 쿼리 옵션을 생성하도록 하는 것이 좋습니다.

클라이언트 및 서버 실행

클라이언트는 쿼리를 두 부분으로 실행합니다. 가능한 경우 쿼리의 식이 클라이언트에서 먼저 계산된 다음 URI 기반 쿼리가 생성되고 서비스의 데이터와 비교하여 평가되도록 데이터 서비스로 보내집니다. 다음 LINQ 쿼리를 살펴보십시오.

Dim basePrice As Integer = 100
Dim discount As Decimal = Convert.ToDecimal(0.1)

' Define a query that returns products based on a 
' calculation that is determined on the client.
Dim productsQuery = From p In context.Products
                  Where p.UnitPrice >
                  (basePrice - (basePrice * discount)) AndAlso
                  p.ProductName.Contains("bike")
                  Select p
int basePrice = 100;
decimal discount = .10M;

// Define a query that returns products based on a 
// calculation that is determined on the client.
var productsQuery = from p in context.Products
                  where p.UnitPrice >
                  (basePrice - (basePrice * discount)) &&
                  p.ProductName.Contains("bike")
                  select p;

이 예에서는 (basePrice – (basePrice * discount)) 식이 클라이언트에서 계산됩니다. 이런 이유로, 데이터 서비스로 보내진 실제 쿼리 URI https://localhost:12345/northwind.svc/Products()?$filter=(UnitPrice gt 90.00M) and substringof('bike',ProductName)에는 필터 절의 90에 대해 계산된 10진수 값이 이미 포함됩니다. 부분 문자열 식을 포함하는 필터링 식의 다른 부분은 데이터 서비스에서 계산됩니다. 클라이언트에서 계산된 식은 CLR(공용 언어 런타임) 의미 체계를 따르지만 데이터 서비스로 보내지는 식은 OData 프로토콜의 데이터 서비스 구현을 활용합니다. 또한 이와 같은 개별 계산으로 인해 클라이언트와 서비스가 서로 다른 시간대에 시간 기반의 계산을 수행하는 경우와 같은 예상치 못한 결과가 발생할 수도 있습니다.

쿼리 응답

DataServiceQuery를 실행하면 요청된 엔터티 형식의 IEnumerable이 반환됩니다. 이 쿼리 결과는 다음 예제와 같이 QueryOperationResponse 개체로 캐스팅될 수 있습니다.

' Execute the query for all customers and get the response object.
Dim response As QueryOperationResponse(Of Customer) = _
    CType(query.Execute(), QueryOperationResponse(Of Customer))
// Execute the query for all customers and get the response object.
QueryOperationResponse<Customer> response = 
    query.Execute() as QueryOperationResponse<Customer>;

데이터 서비스의 엔터티를 나타내는 엔터티 형식 인스턴스는 개체 구체화라는 프로세스에 의해 클라이언트에서 만들어집니다. 자세한 내용은 개체 구체화(WCF Data Services)를 참조하십시오. QueryOperationResponse 개체는 IEnumerable을 구현하여 쿼리 결과에 대한 액세스를 제공합니다.

QueryOperationResponse에는 쿼리 결과에 대한 추가 정보에 액세스할 수 있도록 하는 다음 멤버도 있습니다.

  • Error - 작업에서 오류가 throw된 경우 해당 오류를 가져옵니다.

  • Headers - 쿼리 응답과 연결된 HTTP 응답 헤더의 컬렉션을 포함합니다.

  • Query - QueryOperationResponse를 생성한 원래 DataServiceQuery를 가져옵니다.

  • StatusCode - 쿼리 응답의 HTTP 응답 코드를 가져옵니다.

  • TotalCount - IncludeTotalCount 메서드가 DataServiceQuery에서 호출된 경우 엔터티 집합의 총 엔터티 수를 가져옵니다.

  • GetContinuation - 결과의 다음 페이지 URI를 포함하는 DataServiceQueryContinuation 개체를 반환합니다.

기본적으로 WCF Data Services 는 쿼리 URI에 의해 명시적으로 선택된 데이터만 반환합니다. 이에 따라 필요한 경우 데이터 서비스에서 추가 데이터를 명시적으로 로드하는 옵션이 제공됩니다. 데이터 서비스에서 데이터를 명시적으로 로드할 때마다 요청이 데이터 서비스로 전송됩니다. 명시적으로 로드될 수 있는 데이터에는 관련 엔터티, 페이징 응답 데이터 및 이진 데이터 스트림이 포함됩니다.

Dd673933.note(ko-kr,VS.100).gif참고:
데이터 서비스가 페이징 응답을 반환할 수 있기 때문에 응용 프로그램에서 프로그래밍 패턴을 사용하여 페이징 데이터 서비스 응답을 처리하는 것이 좋습니다. 자세한 내용은 지연된 콘텐츠 로드(WCF Data Services)를 참조하십시오.

쿼리에서 반환되는 데이터의 양은 엔터티의 특정 속성만 응답에서 반환되도록 지정하여 줄일 수도 있습니다. 자세한 내용은 쿼리 프로젝션(WCF Data Services)을 참조하십시오.

집합의 총 엔터티 수 가져오기

일부 시나리오에서는 쿼리에서 반환되는 수뿐만 아니라 엔터티 집합의 총 엔터티 수를 아는 것이 유용합니다. 집합에 있는 이 총 엔터티 수가 쿼리 결과에 포함되도록 요청하려면 DataServiceQueryIncludeTotalCount 메서드를 호출합니다. 이 경우 반환된 QueryOperationResponseTotalCount 속성은 집합의 총 엔터티 수를 반환합니다.

Count 또는 LongCount 메서드를 호출하여 각각 Int32 또는 Int64 값으로 집합의 총 엔터티 수만 가져올 수도 있습니다. 이러한 메서드를 호출하면 QueryOperationResponse가 반환되지 않고 개수 값만 반환됩니다. 자세한 내용은 방법: 쿼리에서 반환되는 엔터티 수 확인(WCF Data Services)을 참조하십시오.

단원 내용

쿼리 프로젝션(WCF Data Services)

개체 구체화(WCF Data Services)

LINQ 고려 사항(WCF Data Services)

방법: 데이터 서비스 쿼리 실행(WCF Data Services)

방법: 데이터 서비스 쿼리에 쿼리 옵션 추가(WCF Data Services)

방법: 쿼리에서 반환되는 엔터티 수 확인(WCF Data Services)

방법: 데이터 서비스 요청에 대한 클라이언트 자격 증명 지정(WCF Data Services)

방법: 클라이언트 요청의 헤더 설정(WCF Data Services)

방법: 쿼리 결과 프로젝션(WCF Data Services)

참고 항목

기타 리소스

WCF Data Services 클라이언트 라이브러리