I used the following methods to construct Order By Expression. Original Source
It is really slick. The downside is it only works if Property is string type.
How can I make it to accept different Property type without creating a bunch of methods for different data types?
public static bool PropertyExists<T>(string propertyName) { return typeof (T).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) != null; } public static Expression<Func<T, string>> GetPropertyExpression<T>(string propertyName) { if (typeof(T).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) == null) { return null; } var paramterExpression = Expression.Parameter(typeof(T)); return (Expression<Func<T, string>>)Expression.Lambda( Expression.PropertyOrField(paramterExpression, propertyName), paramterExpression); }
// orderBy can be either Name or City. if (QueryHelper.PropertyExists<Club>(orderBy)) { var orderByExpression = QueryHelper.GetPropertyExpression<Club>(orderBy); clubQuery = clubQuery.OrderBy(orderByExpression); } else { clubQuery = clubQuery.OrderBy(c => c.Id); }
public class Club { public int Id { get; set; } public string Name { get; set; } public string City { get; set; } public DateTime CreateDate { get; set; } <= this won't work }
public static Expression<Func<TSource, TKey>> GetPropertyExpression<TSource, TKey>(string propertyName) { if (typeof (TSource).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) == null) { return null; } var paramterExpression = Expression.Parameter(typeof (TSource)); return (Expression<Func<TSource, TKey>>) Expression.Lambda(Expression.PropertyOrField( paramterExpression, propertyName), paramterExpression); }
The downside is I end up with a lot of if statements for each datatype.
if (QueryHelper.PropertyExists<Club>(orderBy)) { if(orderBy == "CreateDate") { var orderByExpression = GetPropertyExpression<Club, DateTime>(orderBy); ... } else if(orderBy == "Name" || orderBy == "City") { var orderByExpression = GetPropertyExpression<Club, string>(orderBy); ... } ... } else { clubQuery = clubQuery.OrderBy(c => c.Id); }
I found a solution with the help of Jon Skeet's old answer.
public static class QueryHelper { private static readonly MethodInfo OrderByMethod = typeof (Queryable).GetMethods().Single(method => method.Name == "OrderBy" && method.GetParameters().Length == 2); private static readonly MethodInfo OrderByDescendingMethod = typeof (Queryable).GetMethods().Single(method => method.Name == "OrderByDescending" && method.GetParameters().Length == 2); public static bool PropertyExists<T>(this IQueryable<T> source, string propertyName) { return typeof(T).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) != null; } public static IQueryable<T> OrderByProperty<T>( this IQueryable<T> source, string propertyName) { if (typeof (T).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) == null) { return null; } ParameterExpression paramterExpression = Expression.Parameter(typeof (T)); Expression orderByProperty = Expression.Property(paramterExpression, propertyName); LambdaExpression lambda = Expression.Lambda(orderByProperty, paramterExpression); MethodInfo genericMethod = OrderByMethod.MakeGenericMethod(typeof (T), orderByProperty.Type); object ret = genericMethod.Invoke(null, new object[] {source, lambda}); return (IQueryable<T>) ret; } public static IQueryable<T> OrderByPropertyDescending<T>( this IQueryable<T> source, string propertyName) { if (typeof (T).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) == null) { return null; } ParameterExpression paramterExpression = Expression.Parameter(typeof (T)); Expression orderByProperty = Expression.Property(paramterExpression, propertyName); LambdaExpression lambda = Expression.Lambda(orderByProperty, paramterExpression); MethodInfo genericMethod = OrderByDescendingMethod.MakeGenericMethod(typeof (T), orderByProperty.Type); object ret = genericMethod.Invoke(null, new object[] {source, lambda}); return (IQueryable<T>) ret; } }
string orderBy = "Name"; if (query.PropertyExists(orderBy)) { query = query.OrderByProperty(orderBy); - OR - query = query.OrderByPropertyDescending(orderBy); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With