We decided that in our Silverlight app that we develop we should not waste time writing WCF services manually to interact with data. So we turned to ADO.NET Data Services.
I created a small Web App to host the ADO.NET Data Service which exposed the Entity Framework Model. All fine and dandy, being a bit pedant I created a very small console application just to add a service reference and test the data retrieval. All went well. Then I put the querying logic in the Silverlight app.
Something like
var employees = (from e in GetFreshContext().Employees select e).ToArray();
But upon running in Silverlight (in the console app it ran great) I get thrown with this exception :
System.NotSupportedException: Specified method is not supported.
at System.Data.Services.Client.DataServiceQuery`1. System.Collections.Generic.IEnumerable <TElement>.GetEnumerator()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at MyApp.MainPage..ctor()
at MyApp.App.Application_Startup(Object sender, StartupEventArgs e)
at System.Windows.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, String eventName)
Why?! The very same code doesn't work in Silverlight no matter how I try. Searching on the web desperately, led me in the end to this nice post on the blog called (how ironically?) theproblemsolver : Consuming an ADO.NET Data Service from Silverlight written by Maurice De Beijer
It turns out you can't query synchronously in Silverlight although the exception did **NOT** contain any clue whatsoever regarding this although it should. The correct way :
var query = from t in GetFreshContext().Employee select t;
var dsQuery = (DataServiceQuery<Employee>)query;
dsQuery.BeginExecute(result =>
{
ComboEmployees.ItemsSource = dsQuery.EndExecute(result).ToArray();
}, null);
ComboEmployees.DisplayMemberPath = "FullName";
Then I ran across another problem and it puzzled me for a while too until I found the answer. Specifically I needed to load the Department along with Employee (the entities are different in the real app). Retrieving the list of employees brought the Department property null.
I (might) retrieve a long list of employees so re-querying for each employee entity for the department would be a very costful operation (too many HTTP requests). Looking for solutions I came across Typed Eager Loading Using Entity Framework (& What is Eager Loading vs Deferred Loading) which solves the magic string problem of eager loading but I didn't really care about the string.
I needed the entities eager-loaded. However on Silverlight/ADO.NET Data Services I don't have the option of
DbDataContext.Categories.Include(“Products”)
as presented in the blog post.
Finally it turns out that, as John Papa describes in the MSDN Magazine (Using Silverlight 2 With ADO.NET Data Services), you have an Expand method :
var query = from t in GetFreshContext().Employee.Expand("Department") select t;
var dsQuery = (DataServiceQuery<Employee>)query;
dsQuery.BeginExecute(result =>
{
ComboEmployees.ItemsSource = dsQuery.EndExecute(result).ToArray();
}, null);
ComboEmployees.DisplayMemberPath = "FullName";
Cross posted from http://blog.andrei.rinea.ro/post/2009/08/19/Using-ADONET-Data-Servics-in-Silverlight-3-and-eager-loading-parent-entities.aspx