Search code examples
c#linq-to-entitiesexpression-trees

Linq Expression Tree OrderByDescending with custom comparer


As the title says I'm trying to build an expression tree for source.OrderByDescending(this source, expression, comparer)

This is my code for generating the expression tree:

var orderByDescendingMethod = typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public).First(m => m.Name == "OrderByDescending" && m.GetParameters().Count() == 3).MakeGenericMethod(typeof(Books), typeof(string));
var comparer = Expression.New(typeof(NumericStringComparer));
var orderByFilter = GenerateOrderByPropertyExpression<string>(propertyName);
var comparison = Expression.Call(orderByDescendingMethod, Expression.Constant(books), orderByFilter, comparer);

return Expression.Lambda(comparison);

And the GenerateOrderByPropertyExpression method:

private static Expression<Func<Books, T>> GenerateOrderByPropertyExpression<T>(string propertyName)
{
    var parameter = Expression.Parameter(typeof(Books), "b");
    var property = Expression.Property(parameter, propertyName);
    var toStringMethod = typeof(object).GetMethod("ToString");
    var objectString = Expression.Call(property, toStringMethod);

    return Expression.Lambda<Func<Books, T>>(objectString, parameter);
}

But whenever I call lambda.Compile().DynamicInvoke(); and inspect the result, I get the following error:

LINQ to Entities does not recognize the method 'System.Linq.IOrderedQueryable`1[DataAccess.Plusbog.Books] OrderByDescending[Books,String](System.Linq.IQueryable`1[DataAccess.Plusbog.Books], System.Linq.Expressions.Expression`1[System.Func`2[DataAccess.Plusbog.Books,System.String]], System.Collections.Generic.IComparer`1[System.String])' method, and this method cannot be translated into a store expression.

Any idea what I'm doing wrong? I feel like I'm pretty close.


Solution

  • An excerpt from the Supported and Unsupported LINQ Methods (LINQ to Entities) - Ordering Methods section:

    Most of the LINQ ordering methods are supported in LINQ to Entities, with the exception of those that accept an IComparer<T>, because the comparer cannot be translated to the data source.