1

I'm trying to build a dynamic OrderBy method that I can call repeatedly, unfortunately I keep getting the same error despite implementing code that has been reported to fix it.

I've dissected my code several times whilst referring to two SO posts that have both been reported to work; No generic method 'ThenBy' and No generic method 'ThenBy' on type 'System.Linq.Queryable'

No matter what I do I always receive the error, even if I copy and paste their implementations directly into my code

Error:

InvalidOperationException:

No generic method 'ThenByDescending' 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.

My method:

public static IOrderedQueryable<TEntity> OrderBy<TEntity>(this IOrderedQueryable<TEntity> source, string orderByProperty, bool desc, bool then)
{
    var command = (then ? "Then" : "Order") + (desc ? "ByDescending" : "By");

    var entityType = typeof(TEntity);
    var entityParameter = Expression.Parameter(entityType, "x");

    var property = entityType.GetProperty(orderByProperty);

    var propertyAccess = Expression.MakeMemberAccess(entityParameter, property);
    var orderByExpression = Expression.Lambda(propertyAccess, entityParameter);

    var resultExpression =
        Expression.Call(typeof(Queryable), command, new Type[] { entityType, property.PropertyType }, source.Expression, Expression.Quote(orderByExpression));

    return (IOrderedQueryable<TEntity>)source.Provider.CreateQuery<TEntity>(resultExpression);
}

Calling Method

public IQueryable<T> SortQuery(IQueryable<T> query, Dictionary<string, char> sorts, Dictionary<string, string> sortableProperties)
{
    var count = 0;

    foreach (var s in sorts)
        if (!string.IsNullOrWhiteSpace(s.Key) && new[] {'A', 'D'}.Contains(char.ToUpper(s.Value)))
            query = ((IOrderedQueryable<T>)query).OrderBy(sortableProperties[s.Key], char.ToUpper(s.Value) == 'D', count++ == 0);

    return query;
}

If anybody can shed some light on this it would be greatly appreciated, I've been tearing my hair out for over 3 hours!

Matthew Hudson
  • 1,306
  • 15
  • 36

1 Answers1

1

Cracked it, the problem was that the passed Queryable was just an IQueryable, and not an IOrderedQueryable - Casting doesn't work, it needs to be an IOrderedQueryable.

public IOrderedQueryable<T> SortQuery(IQueryable<T> query, Dictionary<string, char> sorts)
{
    var count = 0;

    var orderedQuery = query.OrderBy(x => true); // This is the fix!

    foreach (var s in sorts)
        if (!string.IsNullOrWhiteSpace(s.Key) && new[] {'A', 'D'}.Contains(char.ToUpper(s.Value)))
            orderedQuery = orderedQuery.OrderBy(this.SortFields[s.Key], char.ToUpper(s.Value) == 'D', count++ == 0);

    return orderedQuery;
}

Kudos to @IvanStoev for setting me on the right track.

Matthew Hudson
  • 1,306
  • 15
  • 36