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로 변환됩니다.
참고: |
---|
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});
참고: |
---|
$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에 대해 지원되지 않습니다.
참고:
빈 시퀀스에서 실행되는 페이징 연산자는 null을 반환합니다.
|
기타 연산자 |
다음과 같은 기타 연산자는 DataServiceQuery에 대해 지원되지 않습니다. |
지원되는 식 함수
다음과 같은 CLR(공용 언어 런타임) 메서드 및 속성은 쿼리 식에서 OData 서비스에 대한 요청 URI에 포함되도록 변환될 수 있으므로 지원됩니다.
String 멤버 | 지원되는 OData 함수 |
---|---|
string concat(string p0, string p1) |
|
bool substringof(string p0, string p1) |
|
bool endswith(string p0, string p1) |
|
int indexof(string p0, string p1) |
|
int length(string p0) |
|
string replace(string p0, string find, string replace) |
|
string substring(string p0, int pos) |
|
string substring(string p0, int pos, int length) |
|
string tolower(string p0) |
|
string toupper(string p0) |
|
string trim(string p0) |
DateTime 멤버1 | 지원되는 OData 함수 |
---|---|
int day(DateTime p0) |
|
int hour(DateTime p0) |
|
int minute(DateTime p0) |
|
int month(DateTime p0) |
|
int second(DateTime p0) |
|
int year(DateTime p0) |
1 Microsoft.VisualBasic.DateAndTime의 해당 날짜 및 시간과 Visual Basic의 DatePart 메서드도 지원됩니다.
Math 멤버 | 지원되는 OData 함수 |
---|---|
decimal ceiling(decimal p0) |
|
double ceiling(double p0) |
|
decimal floor(decimal p0) |
|
double floor(double p0) |
|
decimal round(decimal p0) |
|
double round(double p0) |
Expression 멤버 | 지원되는 OData 함수 |
---|---|
bool isof(type p0) |
또한 클라이언트가 추가 CLR 함수를 계산할 수 있습니다. 클라이언트에서 계산할 수 없고 서버에서 계산하기 위해 올바른 요청 URI로 변환할 수 없는 식에 대해서는 NotSupportedException이 발생합니다.
참고 항목
개념
데이터 서비스 쿼리(WCF Data Services)
쿼리 프로젝션(WCF Data Services)
개체 구체화(WCF Data Services)