2

I want to be able to get an OrderBy query working with a lambda expression so that I get a SQL query with the TOP(n) key word (big performance boost).

I am able to do this if I specifiy ...

PaginatedList = query.OrderBy(x => x.QuoteID).Skip(() => skipValue).Take(() => pageSize)

But because I want the orderBy field to be dynamic through a UI selection of a name I want to do something like this:

var propertyInfo = typeof(Data.Quote).GetProperty(sortName);
Expression<Func<Data.Quote, object>> orderField = x => propertyInfo.GetValue(x, null);
PaginatedList = query.OrderBy(orderField).Skip(() => skipValue).Take(() => pageSize)

This gives me the error:

"LINQ to Entities does not recognize the method 'System.Object GetValue(System.Object)' method, and this method cannot be translated into a store expression."

I tried this that's not of type Expression<Func<T, object>>

var propertyInfo = typeof(Data.Quote).GetProperty(sortName);
Func<Data.Quote, object> orderField = x => propertyInfo.GetValue(x, null);
PaginatedList = query.OrderBy(x => orderField).Skip(() => skipValue).Take(() => pageSize)

And I get this error:

"Unable to create a constant value of type [...]. Only primitive types or enumeration types are supported in this context"

I'm sure there is a way to achieve this but at the moment not sure how.

Saleh
  • 150
  • 10
  • Thanks for all the suggestions everyone best solution I found was in the answer for: http://stackoverflow.com/questions/41244/dynamic-linq-orderby-on-ienumerablet – Saleh Nov 15 '16 at 15:52
  • Have to give the credit to the people who found the duplicate question just about exactly what I needed, big thanks!! been looking for this for ages – Saleh Nov 15 '16 at 16:37

3 Answers3

5

Here is how to achieve what you want:

var propertyInfo = typeof(Data.Quote).GetProperty(sortName);

ParameterExpression parameter = Expression.Parameter(typeof(T), "s");
MemberExpression property = Expression.Property(parameter, propertyInfo);
LambdaExpression sort = Expression.Lambda(property, parameter);

MethodCallExpression call = Expression.Call(
                                         typeof(Queryable),
                                         "OrderBy",
                                         new[] {typeof(T), property.Type},
                                         Query.Expression,
                                         Expression.Quote(sort));

var orderedQuery = (IOrderedQueryable<T>)Query.Provider.CreateQuery<T>(call);

PaginatedList = orderedQuery.Skip(skipValue).Take(pageSize);
Wagner DosAnjos
  • 6,304
  • 1
  • 15
  • 29
3

Instead of that you need to create an expression to select that property.From this source:

public static class Utility
{
    //makes expression for specific prop
    public static Expression<Func<TSource, object>> GetExpression<TSource>(string propertyName)
    {
        var param = Expression.Parameter(typeof(TSource), "x");
        Expression conversion = Expression.Convert(Expression.Property
        (param, propertyName), typeof(object));   //important to use the Expression.Convert
        return Expression.Lambda<Func<TSource, object>>(conversion, param);
    }


    public static IOrderedQueryable<TSource> 
    OrderBy<TSource>(this IQueryable<TSource> source, string propertyName)
    {
        return source.OrderBy(GetExpression<TSource>(propertyName));
    }
}

Then you can order by as I show below:

var result=Query.OrderBy(sortName)...;
ocuenca
  • 38,548
  • 11
  • 89
  • 102
1

The value being copied in to propertyInfo is just an Object, as that is the type returned by GetProperty(). Hover over var and you will confirm this.

The GetValue method doesn't exist for an Object, so you need to cast it to the right type before making the call to GetValue.

LordWilmore
  • 2,829
  • 2
  • 25
  • 30