Vaccano
Vaccano

Reputation: 82467

How to break apart the Linq expression inside an Any clause

I am trying to make a modular Linq query (to an OData source).

This is a simplified version of my query:

// Any clause that I want to be modular
Func<Encounter, bool> orderAnyClause = x => x.OrderName.StartsWith("Order 00");

// Query using the any clause
var result = entities.Customers.Where(cust=> cust.Orders.Any(orderAnyClause));

// A method to do the selection.  It works just fine.
IQueryable<SearchSelectionResult> selectedResults = SelectResults(result); 

// This throws the exception shown below
var list = selectedResults.ToList();  

This all compiles fine, but when I run it my any clause causes this exception:

Unable to cast object of type 'System.Linq.Expressions.ConstantExpression' to type 'System.Linq.Expressions.LambdaExpression'.

I know it is my any clause because if I embed the the clause in the statement, it all works fine.

Why am I getting this error? And how can I break this statement out and not get the error?


Update: Using an Expression

I tried to use an expression like this:

Expression<Func<Encounter, bool>> orderAnyClause = 
                                      x => x.OrderName.StartsWith("Order 00");

And I get the following compile time error message:

Instance argument: cannot convert from System.Data.Services.Client.DataServiceCollection<ODataComponetizedQueriesTest.MyEntities.Order>' to 'System.Linq.IQueryable<ODataComponetizedQueriesTest.MyEntities.Order>'

Upvotes: 0

Views: 673

Answers (2)

Mike Van Til
Mike Van Til

Reputation: 133

You could try defining orderAnyClause like this:

Expression<Func<Encounter, bool>> orderAnyClause = 
                                        x => x.OrderName.StartsWith("Order 00");

I didn't test it, but the way query comprehension works (and based on the error), it wouldn't be able to do anything with it unless it gets it as an expression.

Upvotes: 5

Jon Skeet
Jon Skeet

Reputation: 1502825

Your IQueryable needs to work with expression trees in order to convert the query - in other words, it needs to have a view of the code as data, rather than just as executable code.

Now I'm not 100% sure this will work, but I'd hope that you could use:

Expression<Func<Encounter, bool>> orderAnyClause =
    x => x.OrderName.StartsWith("Order 00");

... and then keep the same code. That way your orderByClause variable refers to an expression tree, not a delegate. Now it's possible that that won't work - because you're using it in another lambda expression here:

cust => cust.Orders.Any(orderAnyClause)

... and that lambda expression will also be converted to an expression tree. It really depends on what the OData provider does with it. You may need to write a method to do funky stuff to build up the cust.Orders.Any(orderAnyClause) - but it's worth trying the simple way first.

Upvotes: 0

Related Questions