7

I am using patterns mentioned here http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

And i am using method below to query EF

public virtual IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null,
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
        string includeProperties = "")
    {
        IQueryable<TEntity> query = dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }
        else
        {
            return query.ToList();
        }
    }

Now i want to create dynamic Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> expression to order my data.

I know only field name as string and order type (ascending, descending) as string (asc, desc)

AlexFoxGill
  • 7,093
  • 2
  • 40
  • 58
bahadir arslan
  • 4,141
  • 6
  • 38
  • 78
  • That is not the usual form for an order-by; have you seen this? http://stackoverflow.com/questions/41244/dynamic-linq-orderby – Marc Gravell Apr 15 '13 at 13:29
  • @MarcGravell thanks, i saw that. But MS's tutorial contains this code so i am trying to write suitable dynamic LINQ for that. Actually i think i succeded but i have to make some tests and then let you know. – bahadir arslan Apr 15 '13 at 13:31

3 Answers3

15

finally i could write the method i want.

 public static Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> GetOrderBy(string orderColumn, string orderType) {
            Type typeQueryable = typeof(IQueryable<TEntity>);
            ParameterExpression argQueryable = Expression.Parameter(typeQueryable, "p");
            var outerExpression = Expression.Lambda(argQueryable, argQueryable);
            string[] props = orderColumn.Split('.');
            IQueryable<TEntity> query = new List<TEntity>().AsQueryable<TEntity>();
            Type type = typeof(TEntity);
            ParameterExpression arg = Expression.Parameter(type, "x");

            Expression expr = arg;
            foreach(string prop in props) {
                PropertyInfo pi = type.GetProperty(prop, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
                expr = Expression.Property(expr, pi);
                type = pi.PropertyType;
            }
            LambdaExpression lambda = Expression.Lambda(expr, arg);
            string methodName = orderType == "asc" ? "OrderBy" : "OrderByDescending";

            MethodCallExpression resultExp =
                Expression.Call(typeof(Queryable), methodName, new Type[] { typeof(TEntity), type }, outerExpression.Body, Expression.Quote(lambda));
            var finalLambda = Expression.Lambda(resultExp, argQueryable);
            return (Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>)finalLambda.Compile();
        }

This method takes two parameters, first one field name other one is asc or desc. Result of method can be used directly with IQueryable object.

Thanks for your helps

bahadir arslan
  • 4,141
  • 6
  • 38
  • 78
6

This is very late to the party but the correct answer is located on another question at https://stackoverflow.com/a/10935223/14275

var students = repository.Get(x => x.FirstName = "Bob",q => q.OrderBy(s => s.LastName));
Community
  • 1
  • 1
Luke
  • 1,816
  • 1
  • 14
  • 15
2

I am not sure what exactly you want to accomplish, but I had changed your code and add some example to demonstrate how does it work.

This is a simple console app, which has dummyText as list. Queryable method enables to use filter and sort expression as you want. I hope it helps

 class Program
{

    private List<string> _dummyText = new List<string>(){ "Arda",
        "Araba",
        "Antartika",
        "Balon"};

    static void Main(string[] args)
    {
        Program p = new Program();
        List<string> result = p.Get(s => s.StartsWith("A"), orderBy: q => q.OrderBy(d => d.Length)).ToList();

        Console.ReadLine();
    }


    public virtual IEnumerable<string> Get(
    Expression<Func<string, bool>> filter = null,
    Func<IQueryable<string>, IOrderedQueryable<string>> orderBy = null)
    {

        IQueryable<string> query = _dummyText.AsQueryable();

        if (filter != null)
        {
            query = query.Where(filter);
        }

        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }
        else
        {
            return query.ToList();
        }



    }

}
Arda
  • 395
  • 4
  • 14
  • thanks for answer but i think there is some misunderstood. I have to send z=>z.OrderBy(x=>x.CreatedDate) to orderBy parameter. So your answer won't work in my opinion. – bahadir arslan Apr 15 '13 at 13:06
  • You can use some external parameters to linq expression to have conditional method execution as inline if...Ex: string direct = "DESC"; List result = p.Get(s => s.StartsWith("A"), orderBy: q => ((direct == "ASC") ? q.OrderBy(d => d.Length) : q.OrderByDescending(d => d.Length))).ToList(); But I quess this is not exactly what you want... – Arda Apr 15 '13 at 13:52