1

How can I dynamically build an order-by expression when only knowing the name of the property (or even the name of a sub-property)?

What I'm trying to achieve is something like:

dbResult = // some database-query as IQueryable<TSource> which is not yet executed;

if (!string.IsNullOrEmpty(request.OrderBy)) { // the user want's to group the results
    var grouped = dbResult.GroupBy(/* this should be build dynamically */);
}

I need something to start with as GroupBy is awaiting a Func<TSource, TKey> but I only know TKey at runtime which can be string, int or even a Guid.

The user could pass something like "Country.Name" to the request.OrderBy property which means the results should be grouped by a sub-property (sub-select), the name of a country.

I think ExpressionTrees is the way to go here but I'm stuck before even getting started as I don't know how to handle the unknown Type as well as the option to group by a property of a sub-select/sub-property.

KingKerosin
  • 3,639
  • 4
  • 38
  • 77
  • 1
    Duplicate? http://stackoverflow.com/questions/7488391/building-an-orderby-expression-using-the-name-of-a-property?rq=1 – Ian Mercer Oct 25 '16 at 18:03
  • @IanMercer: Working for properties of the main-select, but not for sub-properties, e.g. Country.Name as it throws an Exception `Instance property 'Country.Name' is not defined for type 'CountrySelect'` – KingKerosin Oct 25 '16 at 18:24
  • You need to use `Expression.Property` on each property in a chain. See http://stackoverflow.com/questions/11439218/how-can-i-create-a-expression-property-of-a-child-object – Ian Mercer Oct 25 '16 at 18:47
  • Are you seeking for `OrderBy` (as stated in the post title) or `GroupBy`? – Ivan Stoev Oct 25 '16 at 19:16
  • @IvanStoev 'GroupBy'. But OrderBy would for sure be the next step with same requirements – KingKerosin Oct 25 '16 at 19:18
  • `OrderBy` is easy because it doesn't change the element type of the `IQueryable`. But the result of `GroupBy` is `IGrouping`, and you don't have `TKey`, so what is the expected result type - `IQueryable??>`? I mean, building the expression is not hard, but what you will do with the result? It could be non generic `IQueryable`, but it's not very useful. – Ivan Stoev Oct 25 '16 at 19:22

1 Answers1

1

Here is how you can build dynamically a GroupBy expression/query:

public static class QueryableExtensions
{
    public static IQueryable GroupByMember(this IQueryable source, string memberPath)
    {
        var parameter = Expression.Parameter(source.ElementType, "x");
        var member = memberPath.Split('.')
            .Aggregate((Expression)parameter, Expression.PropertyOrField);
        var selector = Expression.Lambda(member, parameter);
        var groupByCall = Expression.Call(typeof(Queryable), "GroupBy",
            new Type[] { parameter.Type, member.Type },
            source.Expression, Expression.Quote(selector));
        return source.Provider.CreateQuery(groupByCall);
    }
}

The problem is though that there is no good generic way of representing the result. And working with non generic IQueryable / IEnumerable is not easy because almost all LINQ methods operate on generic interfaces. Especially with IQueryable you'll find that you need creating more and more methods like this, so you might consider using Dynamic LINQ package.

Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343