1

I came into a project where I need to build some dynamic Queries for EFCore and I needed to make the Queries ordarable by different Attributes and also Asc and DESC.

After I implemented a few Queries with switch case I was asking myself for a generic OrderBy function that can order by a given Attribute-Name and a given SortOrder.

So how to implement a function to do a generic orderBy or orderByDesc on an IQueryable?

Maksym Labutin
  • 533
  • 1
  • 7
  • 16
marvstar
  • 343
  • 3
  • 18
  • I marked this as a duplicate, because the answer to that question applies to Queryable and is also applicable to ef core. – Silvermind Nov 30 '18 at 12:25
  • @Silvermind now you're making me wonder whether we should rename that ancient question, since it also covers `IQueryable` – Marc Gravell Nov 30 '18 at 12:33
  • thx for your reply. I didnt found that answer otherwise i wouldnt have post this Q&A rather than wastet so much time. I guess a rename of that question would lead others that are searching for IQueryable solutions to that answer. – marvstar Nov 30 '18 at 12:44
  • @MarcGravell I had the same feeling. Perhaps add it to the title? – Silvermind Nov 30 '18 at 13:52

1 Answers1

0

In my case my client application is an Angular project which sends the ColumnName (Attribute-Name) as string and the SortOrder as int (-1 DESC, 1 ASC).

With the following extension function its possible to directly Order on an IQueryable based on the Attribute Name and the SortOrder (Could easily be changed to a string).

public static IOrderedQueryable<TSource> ApplyOrderDirection<TSource>(this IQueryable<TSource> source, string attributeName, int sortOrder)
{
    if (String.IsNullOrEmpty(attributeName))
    {
        return source as IOrderedQueryable<TSource>;
    }

    var propertyInfo = typeof(TSource).GetProperty(attributeName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);

    if (propertyInfo == null)
    {
        throw new ArgumentException("ApplyOrderDirection: The associated Attribute to the given AttributeName could not be resolved", attributeName);
    }

    Expression<Func<TSource, object>> orderExpression = x => propertyInfo.GetValue(x, null);

    if (sortOrder > 0)
    {
        return source.OrderBy(orderExpression);
    }
    else
    {
        return source.OrderByDescending(orderExpression);
    }
}

It took me a while to get it work and even to find/build this solution. I hope it can help someone else and save some time.

Rand Random
  • 6,067
  • 9
  • 36
  • 77
marvstar
  • 343
  • 3
  • 18
  • This is fundamentally a LINQ-to-Objects answer (`propertyInfo` won't work with other backends) - it is fortunate that it worked on Angular, but I **very strongly** suspect this will fail with "not supported" errors on most `IQueryable` implementations that *aren't* really LINQ-to-Objects faking it – Marc Gravell Nov 30 '18 at 12:32
  • @MarcGravell what would be a better way to build that expression without propertyInfo? – marvstar Nov 30 '18 at 12:46
  • actually, the problem isn't `PropertyInfo` by itself - it is *how* it is used; the *correct* way to do that is to create an expression tree that represents the desired action *properly*, i.e. `Expression.Property(expr, propertyInfo)`. For a full explanation, please see the answer on the linked question, which has full code – Marc Gravell Nov 30 '18 at 12:52