2

Ok, I found this, which will allow me to do this:

public IList<Item> GetItems(string orderbyColumn)
{
    return _repository.GetItems().OrderBy(orderByColumn).ToList();
}

Is this the best way to do "dynamic" ordering? I want to be able to pass the column name as a string (and the sort direction) to my Service, and have it order the correct way.

Martin
  • 11,031
  • 8
  • 50
  • 77

3 Answers3

9

That's certainly a viable way of doing dynamic sorting. Ch00k provided another option in his answer to this question about "Strongly typed dynamic Linq sorting". I personally prefer Ch00k's method, as there's some compile-time checking involved and there's very little extra code involved.

Community
  • 1
  • 1
Eric King
  • 11,594
  • 5
  • 43
  • 53
  • And his answer (Ch00k) will be refactoring-safe as well, do a rename of a property, and the code updates, with the property name in a string, that won't happen! – Lasse V. Karlsen Sep 27 '09 at 18:22
4

If you've already decided that it must be a string, then your options are somewhat limited. The Dynamic LINQ library would indeed do the job, or if you want t know how it all works, look at this previous answer which builds an Expression from the string at runtime.

At the moment the code only accepts a single member and has separate methods for ascending / descending, but from this example it should be fairly simple to pass a more complex string and split it; essentially as:

IQueryable<T> query = ...
string[] portions = orderBy.Split(' '); // split on space, arbitrarily
if(portions.Length == 0) throw new ArgumentException();
IOrderedQueryable<T> orderedQuery = query.OrderBy(portions[0]);
for(int i = 1 ; i < portions.Length ; i++) { // note we already did the zeroth
    orderedQuery = orderedQuery.ThenBy(portions[i]);
}
return orderedQuery;
Community
  • 1
  • 1
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • It doesn't have to be a string, but how would I pass the sort column from the controller to the Repository/Service? – Martin Sep 29 '09 at 00:52
  • If not a string, then the only other sensible choice would be a lambda Expression, or an object that encapsulates more than one lambda expression. Or just use the existing OrderBy/ThenBy. – Marc Gravell Sep 29 '09 at 04:22
1

If you're just after dynamic sorting without the full Dynamic-Linq stuff you can check out a post I wrote about this a while back: click

EDIT: I don't really blog anymore so here's the actual extension method:

public static IQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string sortExpression) where TEntity : class
    {
        if (string.IsNullOrEmpty(sortExpression))
            return source; // nothing to sort on

        var entityType = typeof(TEntity);
        string ascSortMethodName = "OrderBy";
        string descSortMethodName = "OrderByDescending";            
        string[] sortExpressionParts = sortExpression.Split(' ');
        string sortProperty = sortExpressionParts[0];
        string sortMethod = ascSortMethodName;

        if (sortExpressionParts.Length > 1 && sortExpressionParts[1] == "DESC")
            sortMethod = descSortMethodName;    

        var property = entityType.GetProperty(sortProperty);
        var parameter = Expression.Parameter(entityType, "p");
        var propertyAccess = Expression.MakeMemberAccess(parameter, property);
        var orderByExp = Expression.Lambda(propertyAccess, parameter);

        MethodCallExpression resultExp = Expression.Call(
                                            typeof(Queryable), 
                                            sortMethod, 
                                            new Type[] { entityType, property.PropertyType },
                                            source.Expression, 
                                            Expression.Quote(orderByExp));

        return source.Provider.CreateQuery<TEntity>(resultExp);
    }
ray2k
  • 99
  • 1
  • 3