I'm trying to formulate an Expression for a condition of an EF Core query. What I have so far is an expression that transforms my query result type to an IEnumerable
and a predicate for the type of the IEnumerable
that transforms it into a bool
. Now I want to link them with an Any condition. What I was trying so far is this:
public static Expression<Func<TIn, bool>> Any<TIn, T>(
Expression<Func<TIn, IEnumerable<T>>> valueFunction,
Expression<Func<T, bool>> predicate)
{
var call = Expression.Call(typeof(Queryable), nameof(Queryable.Any), new[] { typeof(T) }, value, predicate);
return Expression.Lambda<Func<TIn, bool>>(call);
}
This throws the following exception:
System.InvalidOperationException : No generic method 'Any' on type 'System.Linq.Queryable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic.
I would imagine that this happens because I try to use the Expression
of the Func
and not a ParameterExpression
to call the Any
method.
So my question is, is it even possible to do that and if yes how? Thank you in advance!
Try this:
public static Expression<Func<TIn, bool>> Any<TIn, T>(
Expression<Func<TIn, IEnumerable<T>>> valueFunction,
Expression<Func<T, bool>> predicate)
{
var method = typeof(Enumerable).GetMethods()
.Where(mi => mi.Name =="Any" && mi.GetParameters().Length == 2)
.Single()
.MakeGenericMethod(typeof(T));
var call = Expression.Call(method, valueFunction.Body, predicate);
return Expression.Lambda<Func<TIn, bool>>(call, valueFunction.Parameters);
}
So you had few issues here. First of all your selector expression returns IEnumerable
so you need to get method from Enumerable
(if you will need to handle IQueryable
's a little more work will be needed, like checking valueFunction.Body.Type
to implement IQueryable
). Then you need to select correct method and since Any
is generic one - you need to set specific type to the type parameters, thus creating a MethodInfo object that represents a particular constructed method (MakeGenericMethod
). And lastly use valueFunction.Body
for one of the Call
arguments.