views:

3210

answers:

2

Background

Currently I have a C# Silverlight business application which uses RIA Services. The application is hosted in ASP.NET using the ADO.NET Entity Framework and a domain service class to read and write to the SQL Server database.

Scenario

I have a server-side method in my DomainServiceClass that returns an IEnumerable list of objects. In my ApplicationName.Web.g.cs file I have an autogenerated function too. In my Silverlight Client Application I want to be able to run a foreach loop over the returned list of objects.

DomainServiceClass Method:

    public IEnumerable<Image> GetJobImages(string jobGuid)
    {
        var query =
            (
             from j in Context.Job
             orderby (j.ShortCode)
             where j.JobID.Equals(jobGuid)
             join a in Context.Audit //.Distinct()
             on j.JobID equals a.Job.JobID
             join i in Context.Image
             on a.Image.JobID equals i.JobID

             select new Image
             {
                 HighResUrl = i.HighResUrl,
                 LowResUrl = i.LowResUrl,
                 UploadDate = i.UploadDate
                 }).AsEnumerable();

        return query;
    }

ApplicationName.Web.g.cs AutoGenerated Function:

    /// <summary>
    /// Returns an EntityQuery for query operation 'GetJobImages'.
    /// </summary>
    public EntityQuery<Image> GetJobImagesQuery(string jobGuid)
    {
        Dictionary<string, object> parameters = new Dictionary<string, object>();
        parameters.Add("jobGuid", jobGuid);
        return base.CreateQuery<Image>("GetJobImages", parameters, false, true);
    }

Silverlight Client Invocation Code:

var context = dds.DomainContext as InmZenDomainContext;
                foreach(var item in context.GetJobImagesQuery(currentJob.JobID.ToString())
                {
                   item.etc.....//
                }

Problem

Unfortunately When I try and invoke this method as above, I receive either the error:

'Cannot implicitly convert type System.Windows.Ria.Data.EntityQuery to System.Collections.IEnumerable'.

OR

'Does not contain a public definition for GetEnumerator'.

After reading and talking to others, I have been informed that I need to change the return type on the AutoGenerated Function (I think).

Question

Does anyone know of a way in which I can change the return type to IEnumerable on this AutoGenerated EntityQuery?! - Or of a different way in which to solve this problem?

Attempted the following:

    /// <summary>
    /// Returns an EntityQuery for query operation 'GetJobImages'.
    /// </summary>
    public IEnumerable<Image> GetJobImagesQuery(string jobGuid)
    {
        Dictionary<string, object> parameters = new Dictionary<string, object>();
        parameters.Add("jobGuid", jobGuid);
        return base.CreateQuery<Image>("GetJobImages", parameters, false, true);
    }

(This fails since the method is autogenerated, it just springs back to what it used to be when I build the solution.)

Help greatly appreciated.

+2  A: 

The problem is that you're missing a step between your call and the IEnumerable collection.

You need to execute the EntityQuery and use LoadOperation to get your results. It's not as straightforward as you'd think, and here's a good forum post that has an example of how to handle things:

How to get a List<> from LoadOperation

Here's the relevant line from the example:

EntityQuery query = Context.GetEmployeesQuery();

Context.Load<Employee>(query).Completed += (sender, args) => {
    List<Employee> list = ((LoadOperation<Employee>)sender).Entities.ToList();
};
Justin Niessner
A: 

You need to load the query and get the results from the load operation. Your Silverlight client invocation code should be modified into something like this:

var context = dds.DomainContext as InmZenDomainContext;
var loadOperation = context.Load(context.GetJobImagesQuery(currentJob.JobID.ToString()));
loadOperation.Completed += (sender, e) => {
  if (!loadOperation.HasError)
    foreach (var item in loadOperation.Entities)
      // Loop over returned items ... Or use LINQ on loadOperation.Entities.
  else
    // loadOperation.Error has details about the error.
    ...
}

Note that all "network calls" are asynchronous in Silverlight.

I would also suggest that you consider changing the query parameter from a string into a GUID.

Martin Liversage
The loadOperation does not have a ".Completed" method available. Nor does it have a ".HasError". Any ideas?
Goober
@Goober: Ups, forgot to use the `DomainContext.Load` method. Hopefully the code is correct. now.
Martin Liversage
Thanks, I fired the code up but to no avail, it all compiles fine, so im beginning to wonder if my Linq Query is in fact correct... :-(
Goober
@Goober: You can debug by placing break points at three locations: First break point is when you call `context.Load`. Next break point is in `GetJobImagesQuery`. Make sure that this method returns a non-empty collection. Third breakpoint is in the `Completed` lambda. The `loadOperation.Entities` should contain the client side versions of the entities returned by `GetJobImagesQuery`. If you are really desperate you can also use a tool like Fiddler to see the data on the wire. If you are using the built-in web server you will have to add a trailing dot after localhost to see traffic in Fiddler.
Martin Liversage