1

Let me start by asking, please don't answer "use AsEnumerable or ToList before", this would get the data into memory and then order. Since I intend to use the same code to apply filter dynamically, that would not be helpfull.

Having this class:

public class Employee {
    public string Name;
    public IEnumerable<string> Childs;
}

I need to be able to sort an IQueryable by Childs property. Since I can't use string.Join directly, I was trying to make it dynamically using Expressions and combine it with a Stored Procedure that would return the names separeted by ",".

The problem is that I wasn't able to merge the procedure call inside the order expression. The order expression that I'm using was taken from this: Dynamic LINQ OrderBy on IEnumerable<T>

public static IOrderedQueryable<T> ApplyOrder<T>(this IQueryable<T> source, string propertyName, string methodName)
{
    string[] properties = propertyName.Split('.');
    Type type = typeof(T);
    ParameterExpression parameter = Expression.Parameter(type);
    Expression expression = parameter;

    PropertyInfo propertyInfo = null;

    foreach (string property in properties)
    {
        propertyInfo = type.GetProperty(property, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase);

        if (propertyInfo.PropertyType.GetInterfaces().Contains(typeof(IEnumerable)))
        {
            /*
                The ideia was to call the procedure here and use it's value to order the source query
            */
        }
        else
        {
            expression = Expression.Property(expression, propertyInfo);
            type = propertyInfo.PropertyType;
        }
    }

    Type orderDelegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
    LambdaExpression orderLambda = Expression.Lambda(orderDelegateType, expression, parameter);

    return (IOrderedQueryable<T>)typeof(Queryable).GetMethods().Single(method => method.Name == methodName && method.IsGenericMethodDefinition && method.GetGenericArguments().Length == 2 && method.GetParameters().Length == 2)
        .MakeGenericMethod(typeof(T), type)
        .Invoke(null, new object[] { source, orderLambda });
}

Honestly I'm studying Expression for a week now and still have no idea where to begin with.

Community
  • 1
  • 1
Fabio Pinto
  • 63
  • 1
  • 8
  • It is Linq-to-Entities, but since the entity framework doesn't know how to translate the method "string.join" into sql, I'm trying to create an expression that will use a procedure that will do that. Maybe that is not the best idea, but couldn't think of any other that would run the query at database, not in memory – Fabio Pinto Apr 06 '15 at 02:01
  • How is this Childs property stored in the db? – MBoros Apr 06 '15 at 19:53
  • They are forein keys to other tables. When the entity framework map the classes they become an ICollection – Fabio Pinto Apr 07 '15 at 23:46
  • So, after a few days searching more, I have found this excelent article that made me realize that I'm trying to do this at the wrong place. I will have to make a new provider and teach it how to work with ICollection (make a subquery). Here is the article's link [link](http://blogs.msdn.com/b/mattwar/archive/2008/11/18/linq-links.aspx) – Fabio Pinto Apr 09 '15 at 14:16
  • I am trying to achieve the same thing. Is there any chance you have an example that I can use? – Fluous Oct 02 '18 at 09:16
  • 1
    @Fluous look at my repository https://github.com/fabiohvp/Datagrid.Net/blob/master/Extensions/Expressions/InternalExpressionExtensions.cs inside GetPropertyExpression method I check for nested properties and create the linq expression recursively. – Fabio Pinto Oct 04 '18 at 03:59

0 Answers0