Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to sort with property name in LINQ OrderBy

Error is

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

My code is

public static GridResult GetAllUsers(int count, int tblsize,string sortcreteria)
{
      using (UserEntities entity = new UserEntities())
      {

          var data = entity.User_Details.Take(count)
.OrderBy(i =>.GetType().GetProperty(sortcreteria).GetValue(i,null))
.Skip(tblsize).ToList();
          result.DataSource = data;
          result.Count = entity.User_Details.Count();
      }
      return result;
}

How to sort with property name as string?

like image 498
Kartheek Avatar asked Apr 15 '13 11:04

Kartheek


2 Answers

Just add the following extension to your code and you're good to go:

using System.Linq;
using System.Linq.Expressions;
using System;

namespace SomeNameSpace
{
    public static class SomeExtensionClass
    {
        public static IQueryable<T> OrderByField<T>(this IQueryable<T> q, string SortField, bool Ascending)
        {
            var param = Expression.Parameter(typeof(T), "p");
            var prop = Expression.Property(param, SortField);
            var exp = Expression.Lambda(prop, param);
            string method = Ascending ? "OrderBy" : "OrderByDescending";
            Type[] types = new Type[] { q.ElementType, exp.Body.Type };
            var mce = Expression.Call(typeof(Queryable), method, types, q.Expression, exp);
            return q.Provider.CreateQuery<T>(mce);
        }
    }

}

Usage:

.OrderByField(sortcriteria, true)

Edit:

For support for the ThenBy method however the following methods returning an IOrderedQueryable should take care of it all:

public static class SomeExtensionClass
{
    private static IOrderedQueryable<T> OrderingHelper<T>(IQueryable<T> source, string propertyName, bool descending, bool anotherLevel)
    {
        var param = Expression.Parameter(typeof(T), "p");
        var property = Expression.PropertyOrField(param, propertyName);
        var sort = Expression.Lambda(property, param);

        var call = Expression.Call(
            typeof(Queryable),
            (!anotherLevel ? "OrderBy" : "ThenBy") + (descending ? "Descending" : string.Empty),
            new[] { typeof(T), property.Type },
            source.Expression,
            Expression.Quote(sort));

        return (IOrderedQueryable<T>)source.Provider.CreateQuery<T>(call);
    }

    public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName)
    {
        return OrderingHelper(source, propertyName, false, false);
    }

    public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName, bool descending)
    {
        return OrderingHelper(source, propertyName, descending, false);
    }

    public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string propertyName)
    {
        return OrderingHelper(source, propertyName, false, true);
    }

    public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string propertyName, bool descending)
    {
        return OrderingHelper(source, propertyName, descending, true);
    }
}
like image 185
2 revs Avatar answered Oct 06 '22 12:10

2 revs


You could try to do this using the (somewhat old) Dynamic LINQ library:

var data = entity.User_Details
    .Take(count)
    .OrderBy(sortcriteria)
    .Skip(tblsize)
    .ToList();

Alternatively, you can still sort the sequence using your original query by moving the objects into memory first, since the LINQ to Entities provider can't translate calls to the Reflection API into SQL:

var data = entity.User_Details
    .Take(count)
    .Skip(tblsize)
    .AsEnumerable()
    .OrderBy(i => i.GetType().GetProperty(sortcriteria).GetValue(i, null))
like image 28
Enrico Campidoglio Avatar answered Oct 06 '22 10:10

Enrico Campidoglio