加载延迟的内容(WCF 数据服务)
默认情况下,WCF 数据服务 会限制查询返回的数据量。 不过,如果需要,您可以从该数据服务显式加载其他数据,包括相关实体、分页响应数据以及二进制数据流。 本主题介绍如何将这种延迟的内容加载到应用程序。
相关实体
执行查询时,仅返回所处理实体集中的实体。 例如,当针对 Northwind 数据服务的某个查询返回 Customers 实体时,默认情况下不会返回相关的 Orders 实体,即使 Customers 和 Orders 之间存在关系也是如此。 此外,如果数据服务中启用了分页,则必须从该服务显式加载后续数据页。 可通过以下两种方法来加载相关实体:
预先加载:您可以使用 $expand 查询选项来请求查询返回由于与查询所请求的实体集的关联而相关的实体。 使用 DataServiceQuery<TElement> 的 Expand 方法将 $expand 选项添加到发送给数据服务的查询。 可以请求多个相关的实体集,方法是用逗号分隔它们,如下面的示例所示。 查询请求的所有实体均在单个响应中返回。 下面的示例将返回 Orders 以及 Order_Details 和 Customers 实体集:
' Define a query for orders that also returns items and customers. Dim query As DataServiceQuery(Of Order) = _ context.Orders.Expand("Order_Details,Customer")
// Define a query for orders that also returns items and customers. DataServiceQuery<Order> query = context.Orders.Expand("Order_Details,Customer");
WCF 数据服务将实体集数量限制为 12,这是可通过使用 $expand 查询选项包括在单个查询中的数量。
显式加载:您可以对 DataServiceContext 实例调用 LoadProperty 方法来显式加载相关实体。 每次调用 LoadProperty 方法都会创建一个对数据服务的单独请求。 下面的示例为 Orders 实体显式加载 Order_Details:
' Explicitly load the order details for each order. context.LoadProperty(order, "Order_Details")
// Explicitly load the order details for each order. context.LoadProperty(order, "Order_Details");
在考虑要使用哪个选项时,请注意在对数据服务的请求数与单个响应中返回的数据量之间进行权衡。 如果您的应用程序需要关联的对象,并且您希望避免因显式检索这些对象的额外请求而导致延迟增加,请使用预先加载。 不过,如果应用程序仅需要特定相关实体实例的数据,则应考虑通过调用 LoadProperty 方法显式加载这些实体。 有关更多信息,请参见如何:加载相关实体(WCF 数据服务)。
分页内容
如果在数据服务中启用了分页,则数据服务返回的源中的项数受数据服务的配置的限制。 可以为每个实体集单独设置页限制。 有关更多信息,请参见配置数据服务(WCF 数据服务)。 启用分页后,源中的最后一项包含指向下一页数据的链接。 此链接包含在一个 DataServiceQueryContinuation<T> 对象中。 通过对执行 DataServiceQuery<TElement> 时返回的 QueryOperationResponse<T> 调用 GetContinuation 方法可以获取指向下一页数据的 URI。 然后,使用返回的 DataServiceQueryContinuation<T> 对象加载下一页结果。 必须先枚举查询结果,然后再调用 GetContinuation 方法。 请考虑使用 do…while 循环首先枚举查询结果,然后再检查 non-null 下一个链接值。 如果 GetContinuation 方法返回 null(在 Visual Basic 中为 Nothing),则表示原始查询没有任何其他结果页。 下面的示例所演示的 do…while 循环从 Northwind 示例数据服务中加载分页的客户数据。
' With a paged response from the service, use a do...while loop
' to enumerate the results before getting the next link.
Do
' Write the page number.
Console.WriteLine("Page {0}:", pageCount + 1)
' If nextLink is not null, then there is a new page to load.
If token IsNot Nothing Then
' Load the new page from the next link URI.
response = CType(context.Execute(Of Customer)(token), _
QueryOperationResponse(Of Customer))
End If
' Enumerate the customers in the response.
For Each customer As Customer In response
Console.WriteLine(vbTab & "Customer Name: {0}", customer.CompanyName)
Next
' Get the next link, and continue while there is a next link.
token = response.GetContinuation()
Loop While token IsNot Nothing
// With a paged response from the service, use a do...while loop
// to enumerate the results before getting the next link.
do
{
// Write the page number.
Console.WriteLine("Page {0}:", pageCount++);
// If nextLink is not null, then there is a new page to load.
if (token != null)
{
// Load the new page from the next link URI.
response = context.Execute<Customer>(token)
as QueryOperationResponse<Customer>;
}
// Enumerate the customers in the response.
foreach (Customer customer in response)
{
Console.WriteLine("\tCustomer Name: {0}", customer.CompanyName);
}
}
// Get the next link, and continue while there is a next link.
while ((token = response.GetContinuation()) != null);
如果某个查询请求在单个响应中与所请求的实体集一起返回相关的实体,则分页限制可能会影响以内联形式包含在该响应中的嵌套源。 例如,如果在 Northwind 示例数据服务中为 Customers 实体集设置了分页限制,则还可以为相关的 Orders 实体集设置单独的分页限制,如下面来自定义 Northwind 示例数据服务的 Northwind.svc.cs 文件的示例所示。
' Set page size defaults for the data service.
config.SetEntitySetPageSize("Orders", 20)
config.SetEntitySetPageSize("Order_Details", 50)
config.SetEntitySetPageSize("Products", 50)
' Paging requires v2 of the OData protocol.
config.DataServiceBehavior.MaxProtocolVersion = _
System.Data.Services.Common.DataServiceProtocolVersion.V2
// Set page size defaults for the data service.
config.SetEntitySetPageSize("Orders", 20);
config.SetEntitySetPageSize("Order_Details", 50);
config.SetEntitySetPageSize("Products", 50);
// Paging requires at least v2 of the OData protocol.
config.DataServiceBehavior.MaxProtocolVersion =
System.Data.Services.Common.DataServiceProtocolVersion.V3;
在这种情况下,必须同时为顶级 Customers 和嵌套的 Orders 实体源实现分页。 下面的示例所演示的 while 循环用于加载与所选 Customers 实体相关的 Orders 实体的页。
While nextOrdersLink IsNot Nothing
For Each o As Order In c.Orders
' Print out the orders.
Console.WriteLine(vbTab & vbTab & "OrderID: {0} - Freight: ${1}", _
o.OrderID, o.Freight)
Next
' Load the next page of Orders.
Dim ordersResponse = _
context.LoadProperty(c, "Orders", nextOrdersLink)
nextOrdersLink = ordersResponse.GetContinuation()
End While
while (nextOrdersLink != null)
{
foreach (Order o in c.Orders)
{
// Print out the orders.
Console.WriteLine("\t\tOrderID: {0} - Freight: ${1}",
o.OrderID, o.Freight);
}
// Load the next page of Orders.
var ordersResponse = context.LoadProperty(c, "Orders", nextOrdersLink);
nextOrdersLink = ordersResponse.GetContinuation();
}
有关更多信息,请参见如何:加载分页结果(WCF 数据服务)。
二进制数据流
通过 WCF 数据服务 能以数据流形式访问二进制大型对象 (BLOB) 数据。 流式处理会将对二进制数据的加载推迟到需要时再加载,并且客户端可以更有效地处理此数据。 为了利用此功能,数据服务必须实现 IDataServiceStreamProvider 提供程序。 有关更多信息,请参见流提供程序(WCF 数据服务)。 启用流式处理后,会在没有相关二进制数据的情况下返回实体类型。 在这种情况下,必须使用 DataServiceContext 类的 GetReadStream 方法从服务访问二进制数据的数据流。 同样,使用 SetSaveStream 方法作为流添加或更改实体的二进制数据。 有关更多信息,请参见使用二进制数据(WCF 数据服务)。