LINQ 고려 사항(WCF Data Services)

이 항목에서는 WCF Data Services 클라이언트를 사용할 때 LINQ 쿼리가 작성되고 실행되는 방식과 Open Data Protocol(OData) 을 구현하는 데이터 서비스를 LINQ로 쿼리할 경우의 제한 사항에 대한 정보를 제공합니다. OData 기반 데이터 서비스에 대해 쿼리를 작성 및 실행하는 방법에 대한 자세한 내용은 데이터 서비스 쿼리(WCF Data Services)를 참조하십시오.

LINQ 쿼리 작성

LINQ 쿼리를 사용하면 IEnumerable을 구현하는 개체의 집합에 대한 쿼리를 작성할 수 있습니다. Visual Studio의 서비스 참조 추가 대화 상자 및 DataSvcUtil.exe 도구를 사용하여 OData 서비스에 대한 표현을 DataServiceContext에서 상속되는 엔터티 컨테이너 클래스로 생성하고 피드에서 반환되는 엔터티를 나타내는 개체를 생성할 수 있습니다. 또한 이러한 도구는 서비스에서 피드로 노출되는 모음의 엔터티 컨테이너 클래스에 대한 속성도 생성합니다. 데이터 서비스를 캡슐화하는 클래스의 해당 속성은 DataServiceQuery을 반환합니다. DataServiceQuery 클래스가 LINQ로 정의된 IQueryable 인터페이스를 구현하기 때문에 WCF Data Services 에서 데이터 서비스를 통해 노출되는 피드에 대해 LINQ 쿼리를 작성할 수 있으며, 이 쿼리는 클라이언트 라이브러리에 의해 실행 시 데이터 서비스로 보내지는 쿼리 요청 URI로 변환됩니다.

Ee622463.Important(ko-kr,VS.100).gif 참고:
LINQ 구문으로 표현할 수 있는 쿼리 집합은 OData 데이터 서비스에 사용되는 URI 구문에서 사용할 수 있는 것보다 광범위합니다. 쿼리를 대상 데이터 서비스의 URI에 매핑할 수 없으면 NotSupportedException이 발생합니다. 자세한 내용은 다음 항목을 참조하십시오. 이 항목의 Unsupported LINQ Methods를 참조하십시오.

다음 예는 운송료가 $30를 초과하는 Orders를 반환하고 결과를 최근 운송 날짜순으로 정렬하는 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

LINQ에 대한 자세한 내용은 Language-Integrated Query (LINQ)를 참조하십시오.

LINQ를 통해 위의 예제와 같은 언어별 선언적 쿼리 구문과 표준 쿼리 연산자로 알려진 쿼리 메서드 집합을 모두 사용하여 쿼리를 작성할 수 있습니다. 위의 예와 동등한 쿼리는 다음 예와 같이 메서드 기반 구문만을 사용하여 작성할 수 있습니다.

Dim selectedOrders = context.Orders _
                     .Where(Function(o) o.Freight.Value > 30) _
                     .OrderByDescending(Function(o) o.ShippedDate)
var selectedOrders = context.Orders
                    .Where(o => o.Freight > 30)
                    .OrderByDescending(o => o.ShippedDate);

WCF Data Services 클라이언트는 두 종류의 작성된 쿼리를 쿼리 URI로 변환할 수 있고 쿼리 식에 쿼리 메서드를 추가하여 LINQ 쿼리를 확장할 수 있습니다. 쿼리 식 또는 DataServiceQuery에 메서드 구문을 추가하여 LINQ 쿼리를 작성할 때 메서드가 호출되는 순서로 연산이 쿼리 URI에 추가됩니다. 이 동작은 AddQueryOption 메서드를 호출하여 쿼리 URI에 각 쿼리 옵션을 추가하는 것과 같습니다.

LINQ 쿼리 실행

First 또는 Single과 같은 쿼리에 추가되는 특정 LINQ 쿼리 메서드로 인해 쿼리가 실행됩니다. 또한 쿼리는 foreach 루프 중이나 쿼리가 List 컬렉션에 할당될 때와 같이 결과가 명시적으로 열거될 때에도 실행됩니다. 자세한 내용은 데이터 서비스 쿼리(WCF Data Services)를 참조하십시오.

클라이언트는 LINQ 쿼리를 두 부분으로 실행합니다. 가능한 경우 쿼리의 LINQ 식이 클라이언트에서 먼저 계산된 다음 URI 기반 쿼리가 생성되고 서비스의 데이터와 비교하여 평가되도록 데이터 서비스로 보내집니다. 자세한 내용은 데이터 서비스 쿼리(WCF Data Services) 단원의 Client versus Server Execution을 참조하십시오.

OData 준수 쿼리 URI에서 LINQ 쿼리를 변환할 수 없는 경우 실행을 시도하면 예외가 발생됩니다. 자세한 내용은 데이터 서비스 쿼리(WCF Data Services)를 참조하십시오.

LINQ 쿼리 예제

이후 단원의 예에서는 OData 서비스에 대해 실행할 수 있는 LINQ 쿼리 종류를 나타냅니다.

필터링

이 단원의 LINQ 쿼리 예는 서비스에서 반환된 피드의 데이터를 필터링합니다.

다음 예는 운송료가 $30를 초과하는 주문만 반환되도록 반환된 Orders 엔터티를 필터링하는 쿼리입니다.

  • LINQ 쿼리 구문 사용:

    Dim filteredOrders = From o In context.Orders
                            Where o.Freight.Value > 30
                            Select o
    
    var filteredOrders = from o in context.Orders
                            where o.Freight > 30
                            select o;
    
  • LINQ 쿼리 메서드 사용:

    Dim filteredOrders = context.Orders.Where(Function(o) o.Freight.Value > 0)
    
    var filteredOrders = context.Orders
        .Where(o => o.Freight > 30);
    
  • URI 쿼리 문자열 $filter 옵션:

    ' Define a query for orders with a Freight value greater than 30.
    Dim filteredOrders _
                = context.Orders.AddQueryOption("$filter", "Freight gt 30M")
    
    // Define a query for orders with a Freight value greater than 30.
    var filteredOrders
        = context.Orders.AddQueryOption("$filter", "Freight gt 30M");
    

위의 모든 예는 쿼리 URI https://localhost:12345/northwind.svc/Orders()?$filter=Freight gt 30M으로 변환됩니다.

정렬

다음 예제는 회사 이름 및 우편 번호를 기준으로 반환된 데이터를 내림차순으로 정렬하는 쿼리를 나타냅니다.

  • LINQ 쿼리 구문 사용:

    Dim sortedCustomers = From c In context.Customers
                                 Order By c.CompanyName Ascending,
                                 c.PostalCode Descending
                                 Select c
    
    var sortedCustomers = from c in context.Customers
                         orderby c.CompanyName ascending, 
                         c.PostalCode descending
                         select c;
    
  • LINQ 쿼리 메서드 사용:

    Dim sortedCustomers = context.Customers.OrderBy(Function(c) c.CompanyName) _
    .ThenByDescending(Function(c) c.PostalCode)
    
    var sortedCustomers = context.Customers.OrderBy(c => c.CompanyName)
        .ThenByDescending(c => c.PostalCode);
    
  • URI 쿼리 문자열 $orderby 옵션:

    Dim sortedCustomers = context.Customers _
                          .AddQueryOption("$orderby", "CompanyName, PostalCode desc")
    
    var sortedCustomers = context.Customers
        .AddQueryOption("$orderby", "CompanyName, PostalCode desc");
    

위의 모든 예는 쿼리 URI https://localhost:12345/northwind.svc/Customers()?$orderby=CompanyName,PostalCode desc로 변환됩니다.

프로젝션

다음 예는 반환된 데이터를 더 좁은 범위의 CustomerAddress 유형으로 프로젝션하는 동등한 쿼리를 나타냅니다.

  • LINQ 쿼리 구문 사용:

    Dim projectedQuery = From c In context.Customers
                         Select New CustomerAddress With
                        {
                            .CustomerID = c.CustomerID,
                            .Address = c.Address,
                            .City = c.City,
                            .Region = c.Region,
                            .PostalCode = c.PostalCode,
                            .Country = c.Country
                        }
    
    var projectedQuery = from c in context.Customers
                select new CustomerAddress
                {
                    CustomerID = c.CustomerID,
                    Address = c.Address,
                    City = c.City,
                    Region = c.Region,
                    PostalCode = c.PostalCode,
                    Country = c.Country
                };
    
  • LINQ 쿼리 메서드 사용:

    Dim projectedQuery = context.Customers.Where(Function(c) c.Country = "Germany") _
                .Select(Function(c) New CustomerAddress With
                {
                    .CustomerID = c.CustomerID,
                    .Address = c.Address,
                    .City = c.City,
                    .Region = c.Region,
                    .PostalCode = c.PostalCode,
                    .Country = c.Country
                })
    
    var projectedQuery = context.Customers.Where(c => c.Country == "Germany")
        .Select(c => new CustomerAddress
        {
            CustomerID = c.CustomerID, 
            Address = c.Address,
            City = c.City,
            Region = c.Region,
            PostalCode = c.PostalCode,
            Country = c.Country});                   
    
Ee622463.note(ko-kr,VS.100).gif참고:
$select 쿼리 옵션은 AddQueryOption 메서드를 사용하여 쿼리 URI에 추가할 수 없습니다. LINQ Select 메서드를 사용하여 클라이언트에서 요청 URI에 $select 쿼리 옵션을 생성하도록 하는 것이 좋습니다.

위의 두 가지 예는 쿼리 URI "https://localhost:12345/northwind.svc/Customers()?$filter=Country eq 'GerGerm'&$select=CustomerID,Address,City,Region,PostalCode,Country"로 변환됩니다.

클라이언트 페이징

다음 예에서는 첫 50개 주문은 건너뛰고 25개 주문을 포함하는 정렬된 주문 엔터티 페이지를 요청하는 쿼리를 나타냅니다.

  • LINQ 쿼리에 쿼리 메서드 적용:

    Dim pagedOrders = (From o In context.Orders
                       Order By o.OrderDate Descending
                       Select o) _
                   .Skip(50).Take(25)
    
    var pagedOrders = (from o in context.Orders
                          orderby o.OrderDate descending
                         select o).Skip(50).Take(25);
    
  • URI 쿼리 문자열 $skip$top 옵션:

    Dim pagedOrders = context.Orders _
                      .AddQueryOption("$orderby", "OrderDate desc") _
                      .AddQueryOption("$skip", 50) _
                      .AddQueryOption("$top", 25) _
    
    var pagedOrders = context.Orders
        .AddQueryOption("$orderby", "OrderDate desc")
        .AddQueryOption("$skip", 50)
        .AddQueryOption("$top", 25);
    

위의 두 가지 예는 쿼리 URI https://localhost:12345/northwind.svc/Orders()?$orderby=OrderDate desc&$skip=50&$top=25로 변환됩니다.

확장

OData 데이터 서비스를 쿼리할 때 쿼리의 대상 엔터티와 관련된 엔터티가 반환된 피드에 포함되도록 요청할 수 있습니다. Expand 메서드는 LINQ 쿼리의 대상인 엔터티 집합에 대한 DataServiceQuery에서 호출되며, 관련 엔터티 집합 이름은 path 매개 변수로 지정됩니다. 자세한 내용은 지연된 콘텐츠 로드(WCF Data Services)를 참조하십시오.

다음 예에서는 쿼리에서 Expand 메서드를 사용하는 여러 가지 동등한 방법을 보여 줍니다.

  • LINQ 쿼리 구문:

    Dim ordersQuery = From o In context.Orders.Expand("Order_Details")
                         Where o.CustomerID = "ALFKI"
                         Select o
    
    var ordersQuery = from o in context.Orders.Expand("Order_Details")
                         where o.CustomerID == "ALFKI"
                         select o;
    
  • LINQ 쿼리 메서드 사용:

    Dim ordersQuery = context.Orders.Expand("Order_Details") _
                              .Where(Function(o) o.CustomerID = "ALFKI")
    
    var ordersQuery = context.Orders.Expand("Order_Details")
                      .Where(o => o.CustomerID == "ALFKI");
    

위의 두 가지 예는 쿼리 URI https://localhost:12345/northwind.svc/Orders()?$filter=CustomerID eq 'ALFKI'&$expand=Order_Details로 변환됩니다.

지원되는 LINQ 메서드

다음 표에는 지원되지 않으며 OData 서비스에 대해 실행되는 쿼리에 포함할 수 없는 LINQ 메서드의 클래스가 나와 있습니다.

연산 유형  지원되지 않는 메서드

집합 연산자

다음을 포함한 모든 집합 연산자는 DataServiceQuery에 대해 지원되지 않습니다.

정렬 연산자:

IComparer이 필요한 다음과 같은 모든 정렬 연산자는 DataServiceQuery에 대해 지원되지 않습니다.

프로젝션 및 필터링 연산자

위치 인수를 허용하는 다음과 같은 프로젝션 및 필터링 연산자는 DataServiceQuery에 대해 지원되지 않습니다.

그룹화 연산자

다음을 포함한 모든 그룹화 연산자는 DataServiceQuery에 대해 지원되지 않습니다.

그룹화 연산은 클라이언트에서 수행되어야 합니다.

집계 연산자

다음을 포함한 모든 집계 연산자는 DataServiceQuery에 대해 지원되지 않습니다.

집계 연산은 클라이언트에서 수행되거나 서비스 작업으로 캡슐화되어야 합니다.

페이징 연산자

다음 페이징 연산자는 DataServiceQuery에 대해 지원되지 않습니다.

Ee622463.note(ko-kr,VS.100).gif참고:
빈 시퀀스에서 실행되는 페이징 연산자는 null을 반환합니다.

기타 연산자

다음과 같은 기타 연산자는 DataServiceQuery에 대해 지원되지 않습니다.

  1. Empty

  2. Range

  3. Repeat

  4. ToDictionary

  5. ToLookup

지원되는 식 함수

다음과 같은 CLR(공용 언어 런타임) 메서드 및 속성은 쿼리 식에서 OData 서비스에 대한 요청 URI에 포함되도록 변환될 수 있으므로 지원됩니다.

String 멤버 지원되는 OData 함수

Concat

string concat(string p0, string p1)

Contains

bool substringof(string p0, string p1)

EndsWith

bool endswith(string p0, string p1)

IndexOf

int indexof(string p0, string p1)

Length

int length(string p0)

Replace

string replace(string p0, string find, string replace)

Substring

string substring(string p0, int pos)

Substring

string substring(string p0, int pos, int length)

ToLower

string tolower(string p0)

ToUpper

string toupper(string p0)

Trim

string trim(string p0)

DateTime 멤버1 지원되는 OData 함수

Day

int day(DateTime p0)

Hour

int hour(DateTime p0)

Minute

int minute(DateTime p0)

Month

int month(DateTime p0)

Second

int second(DateTime p0)

Year

int year(DateTime p0)

1 Microsoft.VisualBasic.DateAndTime의 해당 날짜 및 시간과 Visual Basic의 DatePart 메서드도 지원됩니다.

Math 멤버 지원되는 OData 함수

Ceiling

decimal ceiling(decimal p0)

Ceiling

double ceiling(double p0)

Floor

decimal floor(decimal p0)

Floor

double floor(double p0)

Round

decimal round(decimal p0)

Round

double round(double p0)

Expression 멤버 지원되는 OData 함수

TypeIs

bool isof(type p0)

또한 클라이언트가 추가 CLR 함수를 계산할 수 있습니다. 클라이언트에서 계산할 수 없고 서버에서 계산하기 위해 올바른 요청 URI로 변환할 수 없는 식에 대해서는 NotSupportedException이 발생합니다.

참고 항목

개념

데이터 서비스 쿼리(WCF Data Services)
쿼리 프로젝션(WCF Data Services)
개체 구체화(WCF Data Services)

기타 리소스

OData: URI 규칙