Getting at the LINQ Any Method in Astoria
|
ADO.NET Data Services (pet name: Astoria) has client APIs that you can use to easily code against data services from .NET applications. The main .NET Client Library API can be used in Winforms, Web Apps, WPF, etc. while there is a special client library for use with Silverlight apps. One of the features these client APIs boast is a LINQ implementation that was written specifically to query Astoria services, LINQ to Rest, aka LINQ to Astoria. LINQ to Astoria is limited by the fact that a query must be able to be interpreted into the Astoria syntax. Set operations, i.e. operations that perform some calculation over a set, are among the group of operators not supported by LINQ to Astoria. Count() is an aggregate operation and is an example of the type of operation that is not supported. Not only are they not supported by LINQ to Astoria, they are not supported by the URI syntax either. But there is still a way to get this functionality against your data services - creating custom operations directly in your service. But there's a catch. Queries inside of the data service are not querying the service, they are querying the model that is behind the service. And you have yet another query syntax to deal with - Query Builder methods with Entity SQL Syntax. Rather than get into an entire lesson on that topic, I can point you to the MSDN Documentation on Query Builder methods as well as the Entity SQL reference, then focus my attention back on replicating functionality of a really handy LINQ method that does not have a comparable operator in Entity SQL: the LINQ Any method. I love the Any method. Here's a simple example of what you can do with it: from customer in context.Customers where customer.Orders.Any() select customer; But you can't use that in LINQ to Astoria - the query will fail because Any is not supported. So, the next solution is to create a custom operation in the data service using Query Builder methods and Any. But, you might think you are stuck again because Entity SQL does not have an Any operation. (Even though SQL Server has Any, Entity SQL needs to be able to be translated to any database and Any is not a typical function of many databases, therefore Entity SQL doesn't have it either.) Instead you have to rethink the query and here's trick. Instead of querying for customers with any orders, you can query for customer who have more than zero orders. But that's still a little complicated in Entity SQL if you don't know your way around the syntax. To perform a set operation in Entity SQL you need to use a nested query. Here then is my customer ADO.NET Data Service operation that returns customer with any orders. [WebGet]
"Where" is the query builder method and the it's predicate first does a sub-query, getting all of the orders for each customer (represented by ESQL's generic "it" variable), counting those orders, then seeing if that count is greater than zero. Hopefully, after the explanation, this looks really obvious and you are wondering why I wasted the time. However, without the explanation or the example, there's a pretty good chance you would have wasted a lot of your own time trying to debug the LINQ to Astoria query and another chunk of time trying to figure out why ANY doesn't work in the Entity SQL method. |

