Loading Deferred Content (WCF Data Services)

Important

WCF Data Services has been deprecated and will no longer be available for download from the Microsoft Download Center. WCF Data Services supported earlier versions of the Microsoft OData (V1-V3) protocol only and has not been under active development. OData V1-V3 has been superseded by OData V4, which is an industry standard published by OASIS and ratified by ISO. OData V4 is supported through the OData V4 compliant core libraries available at Microsoft.OData.Core. Support documentation is available at OData.Net, and the OData V4 service libraries are available at Microsoft.AspNetCore.OData.

RESTier is the successor to WCF Data Services. RESTier helps you bootstrap a standardized, queryable, HTTP-based REST interface in minutes. Like WCF Data Services before it, Restier provides simple and straightforward ways to shape queries and intercept submissions before and after they hit the database. And like Web API + OData, you still have the flexibility to add your own custom queries and actions with techniques you're already familiar with.

By default, WCF Data Services limits the amount of data that a query returns. However, you can explicitly load additional data, including related entities, paged response data, and binary data streams, from the data service when it is needed. This topic describes how to load such deferred content into your application.

When you execute a query, only entities in the addressed entity set are returned. For example, when a query against the Northwind data service returns Customers entities, by default the related Orders entities are not returned, even though there is a relationship between Customers and Orders. Also, when paging is enabled in the data service, you must explicitly load subsequent data pages from the service. There are two ways to load related entities:

  • Eager loading: You can use the $expand query option to request that the query return entities that are related by an association to the entity set that the query requested. Use the Expand method on the DataServiceQuery<TElement> to add the $expand option to the query that is sent to the data service. You can request multiple related entity sets by separating them by a comma, as in the following example. All entities requested by the query are returned in a single response. The following example returns Order_Details and Customers together with the Orders entity set:

    // Define a query for orders that also returns items and customers.
    DataServiceQuery<Order> query =
        context.Orders.Expand("Order_Details,Customer");
    
    ' Define a query for orders that also returns items and customers.
    Dim query As DataServiceQuery(Of Order) = _
    context.Orders.Expand("Order_Details,Customer")
    

    WCF Data Services limits to 12 the number of entity sets that can be included in a single query by using the $expand query option.

  • Explicit loading: You can call the LoadProperty method on the DataServiceContext instance to explicitly load related entities. Each call to the LoadProperty method creates a separate request to the data service. The following example explicitly loads Order_Details for an Orders entity:

    // 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")
    

When you consider which option to use, realize that there is a tradeoff between the number of requests to the data service and the amount of data that is returned in a single response. Use eager loading when your application requires associated objects and you want to avoid the added latency of additional requests to explicitly retrieve them. However, if there are cases when the application only needs the data for specific related entity instances, you should consider explicitly loading those entities by calling the LoadProperty method. For more information, see How to: Load Related Entities.

Paged Content

When paging is enabled in the data service, the number of entries in the feed that the data service returns is limited by the configuration of the data service. Page limits can be set separately for each entity set. For more information, see Configuring the Data Service. When paging is enabled, the final entry in the feed contains a link to the next page of data. This link is contained in a DataServiceQueryContinuation<T> object. You obtain the URI to the next page of data by calling the GetContinuation method on the QueryOperationResponse<T> returned when the DataServiceQuery<TElement> is executed. The returned DataServiceQueryContinuation<T> object is then used to load the next page of results. You must enumerate the query result before you call the GetContinuation method. Consider using a do…while loop to first enumerate the query result and then check for a non-null next link value. When the GetContinuation method returns null (Nothing in Visual Basic), there are no additional result pages for the original query. The following example shows a do…while loop that loads paged customer data from the Northwind sample data service.

// 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);
' 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

When a query requests that related entities are returned in a single response together with the requested entity set, paging limits may affect nested feeds that are included inline with the response. For example, when a paging limit is set in the Northwind sample data service for the Customers entity set, an independent paging limit can also be set for the related Orders entity set, as in the following example from the Northwind.svc.cs file that defines the Northwind sample data service.

// 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 v2 of the OData protocol.
config.DataServiceBehavior.MaxProtocolVersion = _
    System.Data.Services.Common.DataServiceProtocolVersion.V2

In this case, you must implement paging for both the top-level Customers and the nested Orders entity feeds. The following example shows the while loop used to load pages of Orders entities related to a selected Customers entity.

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();
}
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

For more information, see How to: Load Paged Results.

Binary Data Streams

WCF Data Services enables you to access binary large object (BLOB) data as a data stream. Streaming defers the loading of binary data until it is needed, and the client can more efficiently process this data. In order to take advantage of this functionality, the data service must implement the IDataServiceStreamProvider provider. For more information, see Streaming Provider. When streaming is enabled, entity types are returned without the related binary data. In this case, you must use the GetReadStream method of the DataServiceContext class to access the data stream for the binary data from the service. Similarly, use the SetSaveStream method to add or change binary data for an entity as a stream. For more information, see Working with Binary Data.

See also