Reputation: 188
I wish to Create the following Linq expression using Expression tree:
var result2 = soldiers.OrderByDescending(soldier => soldier.Ranks.OrderBy(r=> r.Date).FirstOrDefault().Date).ToArray() ;
The models are listed at the end of the question
I tried to do the following:
ParameterExpression pe = Expression.Parameter(typeof(Soldier), "soldier");
// e.g soldier.ranks
MemberExpression rank = Expression.Property(pe, "ranks");
ParameterExpression nestedParams = Expression.Parameter(typeof(Rank), "rank");
var dateProperty = typeof(Rank).GetProperty("Date");
// e.g rank.Date
MemberExpression nestedExpression= Expression.MakeMemberAccess(nestedParams, dateProperty);
// e.g rank => rank.date
var orderByExp = Expression.Lambda<Func<Rank, DateTime?>>(nestedExpression, nestedParams);
MethodCallExpression orderByCallExpression2 = Expression.Call(
typeof(Queryable),
"OrderByDescending",
new Type[] { typeof(Rank), typeof(DateTime?) },
rank, ***// i suspect the problem is in this line #110***
orderByExp);
But the following error has been thorwn:
System.InvalidOperationException: 'No generic method 'OrderByDescending' 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. '
As I wrote in the code's comments, I suspect that the problem occurs becuase of line 110.
I tried to concatenate the orderBy method on the soldier.ranks
property.
But perhaps becuase the `soldier.ranks is MemberExpression instead of MethodCallExpression or Queryable, i couldn't preformed that action.
I used both links as reference but could find, anything similler to my problem. * https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/how-to-use-expression-trees-to-build-dynamic-queries
*https://stackoverflow.com/a/11337472/10950549
models:
public class Soldier
{
public Rank Rank {
get {
return this.Ranks.OrderByDescending(m => m.Date).FirstOrDefault();
}
}
public ICollection<Rank> Ranks { get; set; }
}
public class Rank
{
public int Id { get; set; }
public DateTime? Date { get; set; }
}
thanks,
Upvotes: 3
Views: 418
Reputation: 205629
I suspect that the problem occurs because of line 110
MethodCallExpression orderByCallExpression2 = Expression.Call(
typeof(Queryable),
"OrderByDescending",
new Type[] { typeof(Rank), typeof(DateTime?) },
rank, ***// i suspect the problem is in this line #110***
orderByExp);
Nope, the problem is the Queryable
3 lines above:
typeof(Queryable),
It doesn't matter what exact type of expression (member, method call etc.) rank
is, the important is what is the type of the result of that expression (i.e. Expression.Type
). And the type of soldier.Ranks
is ICollection<Rank>
- definitely not IQueryable<Rank>
, hence the exception.
But as we know, ICollection<T>
inherits (is a) IEnumerable<T>
, hence oldier.Ranks.OrderBy
is actually call to Enumerable.OrderBy
rather than Queryable.OrderBy
.
With that being said, simply change Queryable
to Enumerable
in the aforementioned line and this particular problem will be solved.
Upvotes: 3