How to dynamically build Order By Expression in Entity Framework?

I used the following methods to build Order By Expression . Source source

This is really a stain. The disadvantage is that it only works if the property is a string .

How can I make it accept different types of properties 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); } 

Using

 // 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); } 

Problem

 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 } 

My current approach (too many if statements)

 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 that in the end I get a lot of if statements for each data type.

 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); } 
+15
source share
1 answer

I found a solution using Jon Skeet 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>(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; } } 

Using

 string orderBy = "Name"; if (QueryHelper.PropertyExists<Club>(orderBy)) { query = query.OrderByProperty(orderBy); - OR - query = query.OrderByPropertyDescending(orderBy); } 
+21
source

Source: https://habr.com/ru/post/1246037/


All Articles