Tip: Getting Hierarchical Entities via ADO.NET Data Services from Silverlight

ADO.NET Data Services (hereafter called Astoria) allows simple URI mapping to entity models. Pretty cool. We can also dive into the entity model and return hierarchical data. For example, a set of Customer entities can be returned without their children or the Customer can be returned with their children (their associated Orders entities). Here are some sample syntaxes for these …

So the following URI would get all of the customer entities

http://[yourdomain]/NorthwindDataService.svc/customers()

And the following URI gets you all the customers and all of their orders:

http://[yourdomain]/NorthwindDataService.svc/customers()?$expand=orders 

But what if you want to get grandchild entities? For example, getting the Customers, their orders, and the order details for those orders. The following URI does not work ….

http://[yourdomain]/NorthwindDataService.svc/customers(‘ALFKI’)?$expand=orders,orderdetails

That will yield an error of “Type 'NorthwindModel.Customer' does not have a property named 'OrderDetails'.” When the expand keyword sees a comma delimited list, it tries to associate that entityset with the one in the URI. In other words it looks for a property on the Customers entity for Orders and one for OrderDetails. OrderDetails does not exist on the Customers (its on the Orders) so it fails.

So how do you get hierarchical data like this? Here is an example that works. This gets the customer ALFKI, its orders, and its orders order details. This example shows the expand keyword has 2 parameters: Orders and Orders/OrderDetails.

http://[yourdomain]/NorthwindDataService.svc/Customers('ALFKI')?$expand=Orders,Orders/OrderDetails

Interestingly, a shortcut to the previous example that also works eliminates the first parameter (the Orders) but yields the same good results of a customer, his orders and his orders’ order details. When diving into a grandchild hierarchy like this, the Orders entities are implied. In other words, since we grab the customer and we are asking for its OrderDetails, it is implied that we want the orders that connect the customers to their order details.

http://[yourdomain]/NorthwindDataService.svc/Customers('ALFKI')?$expand=Orders/OrderDetails

So we can use the comma to ask for multiple entitysets hanging off an entityset or we can use the slash to dive into a hierarchy. In Silverlight we don’t need to use the URI, we can use LINQ to specify the queries (which then get translated to the URIs).

Both of the following LINQ queries will get the customers, their orders and their order details.

var query =
from c in Context.Customers.Expand("Orders/OrderDetails")
select c;

OR

var query =
from c in Context.Customers.Expand("Orders").Expand("Orders/OrderDetails")
select c;

So there you have it!

NOTE: The more data you request, the larger the return set (obviously). Only request data you need. If you might need more data later, you can always ask for it using another URI call or possibly using the BeginLoadProperty from Silverlight. More on this in another post :)