I'm trying to get my head around combining expressions, looking around it should be possible to do what I'm trying to do but I'm struggling.
I have an Expression<Func<class, dynamic>>
which defines my selection that I eventually run against my EF context, where class
is a table I'm selecting data from. For example:
Expression<Func<foo, dynamic>> expression = foo => new
{
RecordExists = foo.bar.Exists,
RecordHasPaid = foo.bar.Amount != null && foo.bar.Amount > 0
}
// run the expression against the database and get the results...
var results = context.foo.Select(expression);
What I want to be able to do is to then extract common logic within that expression out into static "helper" style expressions I can re-use, for example, rather than having this line within my first expression
RecordHasPaid = foo.bar.Amount != null && foo.bar.Amount > 0
I could have a re-usable expression, stored in a re-usable class, say ExpressionHelper
, that I can then insert into my first expression:
public static Expression<Func<bar, bool>> BarHasPaid(bar foobar)
{
return b => b.Amount != null && b.Amount > 0;
}
Becomes:
Expression<Func<foo, dynamic>> expression = foo => new
{
RecordExists = foo.bar.Exists,
RecordHasPaid = ExpressionHelper.BarHasPaid(foo.bar)
}
// run the expression against the database and get the results...
var results = context.foo.Select(expression);
Note that I am passing in a different parameter to this expression than my outer expression (hopefully I can be that generic).
Sounds great, compiles fine, however - when I come to run the .Select I get the dreaded error:
LINQ to Entities does not recognize the method 'System.Linq.Expressions.Expression1[System.Func2[bar,System.Boolean]] BarHasPaid(bar)' method, and this method cannot be translated into a store expression.
I understand the reason why this happens (at least I think I do) in that my method is not known so cannot be translated into SQL, and additionally my expression cannot be turned into an Expression Tree which makes sense to EF because I am essentially using two different expressions within each other and it doesn't know how to turn them into something that makes sense.
I've tried various things, combining the expressions such as here which unfortunately seems to work when you have two expressions, not one expression inside another expression.
I've also tried implementing the wrap/unwrap with custom ExpressionVisitors as mentioned here (I did eventually get this to compile fine, but I get the same error)
I've also tried many other similar answers and tried using LinqKit to Expand
my expression and also set my context with AsExpandable
to no avail. All of my attempts so far have resulted in either the above error, or this one when trying to combine using LambdaExpression.Lambda
to compile my combined expression:
variable 'foo' of type referenced from scope '' but it is not defined
Which I believe is being thrown because the variable foo
which is used within my outer expression, Expression<Func<foo, dynamic>>
, does not exist within my expression Expression<Func<bar, bool>>
because the resulting expression when they are combined would make no sense.
Unfortunately I don't think I have a deep enough understanding of exactly what it is I'm trying to do, so I've hit a bit of a dead end as to where to turn next. Any suggestions as to if this is possible and/or how to achieve it would be greatly appreciated.
EDIT: I have created two sample projects using Rextester, this is the working example and this is what causes the error - using this online tool you can actually see what EF should be running but as there is no EF to run it against the error doesn't actually occur during that test.