Print Page | Close Window

IEnumerable named query with includes not working

Printed From: IdeaBlade
Category: DevForce
Forum Name: DevForce 2010
Forum Discription: For .NET 4.0
URL: http://www.ideablade.com/forum/forum_posts.asp?TID=3387
Printed Date: 13-May-2026 at 8:27am


Topic: IEnumerable named query with includes not working
Posted By: AuerRo
Subject: IEnumerable named query with includes not working
Date Posted: 11-Apr-2012 at 7:55am
Hi,
I have a named query returning IEnumerable<T> like this:


public IEnumerable<Customer> GetCustomerWithCalculations()
{
    var entities = new EntityQuery<Customer>()
        .Include(Customer.PathFor(x => x.City.Region.Nation.Continent))
        .Where(x => x.Name.StartsWith("A"))
        .Execute();

    entities.ForEach(x =>
                         {
                             x.CalculateRevenue();
                             x.CalculateOpenAmount();
                         });

    return entities;
}



Everything except the include works as expected. If I change the named query to return IQueryable<T>, the include works as expected, but of course the ForEach has no effect. The calculations have to be on the server side, so in the end IQueryable<T> is no option.

I did not find anything like this mentioned in the docs, so I assume this is an error on my side. But I have no idea what to change that the include takes affect!

Thanks for any hint to solve this in advance!

Best regards, Roland



Replies:
Posted By: DenisK
Date Posted: 12-Apr-2012 at 3:51pm
Hi Roland,

I'm able to see the issue here. I'm going to check with a senior engineer to find out whether this is a bug or just a known limitation when returning an IEnumerable. 

FYI, the Include works on the server, i.e. inside the named query, you can actually see that the included entities are being returned from the db to the server. They're just not being returned/serialized from the server to the client as well.

Since you must execute the calculations on the server, one suggestion is to return IQueryable, intercept the query results on the server and execute the calculations. This way you can keep the client side query call the same and not have to change anything there.

public class MyQueryInterceptor : EntityServerQueryInterceptor {
  protected override bool ExecuteQuery() {

      //calls base.ExecuteQuery to execute and returns results
      base.ExecuteQuery();

      //Do special calculations for your particular named query here
      PerformAdditionalCalculationsToCustomerResults();
  }
  
  private void PerformAdditionalCalculationsToCustomerResults() {
      var entityQuery = this.Query as EntityQuery;

      if (entityQuery != null && 
          entityQuery.IsNamedQuery && 
          entityQuery.NamedQueryMethod.Name.Contains("CustomerWithCalculations")) {
        
          if (this.QueriedEntities.Any()) {
            this.QueriedEntities.OfType<Customer>().ForEach(c => {
                                                 c.CalculateRevenue();
                                                 c.CalculateOpenAmount();
                                              });
          }
      }
   }
}

Another suggestion that does require you to change client side code is to use Remote Server Method. See  http://drc.ideablade.com/xwiki/bin/view/Documentation/rsmc-query - http://drc.ideablade.com/xwiki/bin/view/Documentation/rsmc-query . This is just another option.

I'll keep you updated as to whether this is a bug or not.


Posted By: AuerRo
Date Posted: 13-Apr-2012 at 1:05am
Hi Denis!

Thanks for your help!

I implemented the solution "Named queryable and using the EntityServerQueryInterceptor" and it works. I assume that your ExecuteQuery-mehtod should rather look like this:
 
protected override bool ExecuteQuery() {

      //calls base.ExecuteQuery to execute and returns results
      var baseQueryResult = base.ExecuteQuery();

      //Do special calculations for your particular named query here
if(baseQueryResult)
      PerformAdditionalCalculationsToCustomerResults();

return baseQueryResult;
  }
Anyway, I'm not fully satisfied with this solution, as I'm force to tear one query into two parts. As the pattern of these queries is always the same (defaultquery + includes + where-constraint + entity-calculations) I was wondering, if I need the named query at all.

There is a Tag-property in every EntityQuery. Can I add a custom string value (eg: "ApplyCustomerCalculations") on the client as EntityQuery.Tag, check this Tag value on the server in the EntityServerQueryInterceptor.ExecuteQuery and start the same calculations? So I wouldn't need the named query, and everything stays in two places, not in three (means Client-Repository - ESQInterceptor and not Client-Repository - NamedQuery - ESQInterceptor).

Of course, overall, I'd prefer to be able to solve this in a named query only, so I'd rather hope this is a bug than a feature. ;)

Have a nice weekend
Roland


Posted By: DenisK
Date Posted: 13-Apr-2012 at 11:36am
Yes, you're correct. Of course we want to check if base.ExecuteQuery succeeds or not. 

Your suggestion of using EntityQuery.Tag is certainly another option. And yes, you can assign it a custom string and check the value on the server. I didn't suggest it since I was thinking you want to keep the named query call structure the same so you can easily remove the interceptor part if it turns out to be a bug and it's fixed.


Posted By: DenisK
Date Posted: 16-Apr-2012 at 5:21pm
Hi Roland,

It turns out that this is not a bug. This is something that we just don't support. An Include can only work with an EntityQuery. We can, however, add this as a feature if we have more requests for this type of scenario in the future.



Print Page | Close Window