Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I do an OrderBy with a dynamic string parameter?

I want to do this:

var orderBy = "Nome, Cognome desc";

var timb = time.Timbratures.Include("Anagrafica_Dipendente")
    .Where(p => p.CodDipendente == 1);

if(orderBy != "")
    timb = timb.OrderBy(orderBy);

Is there an OrderBy overload available that accepts a string parameter?

like image 329
Luca Romagnoli Avatar asked Apr 28 '10 09:04

Luca Romagnoli


5 Answers

If you are using plain LINQ-to-objects and don't want to take a dependency on an external library it is not hard to achieve what you want.

The OrderBy() clause accepts a Func<TSource, TKey> that gets a sort key from a source element. You can define the function outside the OrderBy() clause:

Func<Item, Object> orderByFunc = null;

You can then assign it to different values depending on the sort criteria:

if (sortOrder == SortOrder.SortByName)
  orderByFunc = item => item.Name;
else if (sortOrder == SortOrder.SortByRank)
  orderByFunc = item => item.Rank;

Then you can sort:

var sortedItems = items.OrderBy(orderByFunc);

This example assumes that the source type is Item that have properties Name and Rank.

Note that in this example TKey is Object to not constrain the property types that can be sorted on. If the func returns a value type (like Int32) it will get boxed when sorting and that is somewhat inefficient. If you can constrain TKey to a specific value type you can work around this problem.

like image 196
Martin Liversage Avatar answered Nov 08 '22 11:11

Martin Liversage


Absolutely. You can use the LINQ Dynamic Query Library, found on Scott Guthrie's blog. There's also an updated version available on CodePlex.

It lets you create OrderBy clauses, Where clauses, and just about everything else by passing in string parameters. It works great for creating generic code for sorting/filtering grids, etc.

var result = data
    .Where(/* ... */)
    .Select(/* ... */)
    .OrderBy("Foo asc");

var query = DbContext.Data
    .Where(/* ... */)
    .Select(/* ... */)
    .OrderBy("Foo ascending");
like image 28
Mike Mooney Avatar answered Nov 08 '22 12:11

Mike Mooney


Another solution from codeConcussion (https://stackoverflow.com/a/7265394/2793768)

var param = "Address";    
var pi = typeof(Student).GetProperty(param);    
var orderByAddress = items.OrderBy(x => pi.GetValue(x, null));
like image 36
Chris Phan Avatar answered Nov 08 '22 13:11

Chris Phan


The simplest & the best solution:

mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s));
like image 27
Ramy Yousef Avatar answered Nov 08 '22 13:11

Ramy Yousef


You don't need an external library for this. The below code works for LINQ to SQL/entities.

    /// <summary>
    /// Sorts the elements of a sequence according to a key and the sort order.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of <paramref name="query" />.</typeparam>
    /// <param name="query">A sequence of values to order.</param>
    /// <param name="key">Name of the property of <see cref="TSource"/> by which to sort the elements.</param>
    /// <param name="ascending">True for ascending order, false for descending order.</param>
    /// <returns>An <see cref="T:System.Linq.IOrderedQueryable`1" /> whose elements are sorted according to a key and sort order.</returns>
    public static IQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> query, string key, bool ascending = true)
    {
        if (string.IsNullOrWhiteSpace(key))
        {
            return query;
        }

        var lambda = (dynamic)CreateExpression(typeof(TSource), key);

        return ascending 
            ? Queryable.OrderBy(query, lambda) 
            : Queryable.OrderByDescending(query, lambda);
    }

    private static LambdaExpression CreateExpression(Type type, string propertyName)
    {
        var param = Expression.Parameter(type, "x");

        Expression body = param;
        foreach (var member in propertyName.Split('.'))
        {
            body = Expression.PropertyOrField(body, member);
        }

        return Expression.Lambda(body, param);
    }

(CreateExpression copied from https://stackoverflow.com/a/16208620/111438)

like image 24
niaher Avatar answered Nov 08 '22 12:11

niaher