public static class StringFieldNameSortingSupport
{
#region Private expression tree helpers
private static LambdaExpression GenerateSelector<TEntity>(String propertyName, out Type resultType)
where TEntity : class
{
// Create a parameter to pass into the Lambda expression (Entity => Entity.OrderByField).
var parameter = Expression.Parameter(typeof(TEntity), "Entity");
// create the selector part, but support child properties
PropertyInfo property;
Expression propertyAccess;
if (propertyName.Contains('.'))
{
// support to be sorted on child fields.
String[] childProperties = propertyName.Split('.');
property = typeof(TEntity).GetProperty(childProperties[0]);
propertyAccess = Expression.MakeMemberAccess(parameter, property);
for (int i = 1; i < childProperties.Length; i++)
{
property = property.PropertyType.GetProperty(childProperties[i]);
propertyAccess = Expression.MakeMemberAccess(propertyAccess, property);
}
}
else
{
property = typeof(TEntity).GetProperty(propertyName);
propertyAccess = Expression.MakeMemberAccess(parameter, property);
}
resultType = property.PropertyType;
// Create the order by expression.
return Expression.Lambda(propertyAccess, parameter);
}
private static MethodCallExpression GenerateMethodCall<TEntity>(
IQueryable<TEntity> source,
string methodName,
String fieldName
) where TEntity : class
{
Type type = typeof(TEntity);
Type selectorResultType;
LambdaExpression selector = GenerateSelector<TEntity>(fieldName, out selectorResultType);
MethodCallExpression resultExp = Expression.Call(typeof(Queryable), methodName,
new Type[] { type, selectorResultType },
source.Expression, Expression.Quote(selector)
);
return resultExp;
}
#endregion
public static IOrderedQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source,
string fieldName) where TEntity : class
{
MethodCallExpression resultExp = GenerateMethodCall<TEntity>(source, "OrderBy", fieldName);
return source.Provider.CreateQuery<TEntity>(resultExp) as IOrderedQueryable<TEntity>;
}
public static IOrderedQueryable<TEntity> OrderByDescending<TEntity>(this IQueryable<TEntity> source,
string fieldName) where TEntity : class
{
MethodCallExpression resultExp = GenerateMethodCall<TEntity>(source, "OrderByDescending",
fieldName);
return source.Provider.CreateQuery<TEntity>(resultExp) as IOrderedQueryable<TEntity>;
}
public static IOrderedQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source,
string fieldName, SortDirection direction) where TEntity : class
{
if (direction == SortDirection.Descending)
return StringFieldNameSortingSupport.OrderByDescending(source, fieldName);
else
return StringFieldNameSortingSupport.OrderBy(source, fieldName);
}
public static IOrderedQueryable<TEntity> ThenBy<TEntity>(this IOrderedQueryable<TEntity> source,
string fieldName) where TEntity : class
{
MethodCallExpression resultExp = GenerateMethodCall<TEntity>(source, "ThenBy", fieldName);
return source.Provider.CreateQuery<TEntity>(resultExp) as IOrderedQueryable<TEntity>;
}
public static IOrderedQueryable<TEntity> ThenByDescending<TEntity>(this IOrderedQueryable<TEntity> source,
string fieldName) where TEntity : class
{
MethodCallExpression resultExp = GenerateMethodCall<TEntity>(source,
"ThenByDescending",
fieldName);
return source.Provider.CreateQuery<TEntity>(resultExp) as IOrderedQueryable<TEntity>;
}
public static IOrderedQueryable<TEntity> ThenBy<TEntity>(this IOrderedQueryable<TEntity> source,
string fieldName, SortDirection direction) where TEntity : class
{
if (direction == SortDirection.Descending)
return StringFieldNameSortingSupport.ThenBy(source, fieldName);
else
return StringFieldNameSortingSupport.ThenByDescending(source, fieldName);
}
public static IOrderedQueryable<TEntity> OrderUsingSortExpression<TEntity>(this IQueryable<TEntity> source,
string sortExpression) where TEntity : class
{
String[] orderFields = sortExpression.Split(',');
IOrderedQueryable<TEntity> result = null;
for (int currentFieldIndex = 0; currentFieldIndex < orderFields.Length; currentFieldIndex++)
{
String[] expressionPart = orderFields[currentFieldIndex].Trim().Split(' ');
String sortField = expressionPart[0];
Boolean sortDescending = (expressionPart.Length == 2) && (expressionPart[1].Equals("DESC", StringComparison.OrdinalIgnoreCase));
if (sortDescending)
{
result = currentFieldIndex == 0 ? source.OrderByDescending(sortField) : result.ThenByDescending(sortField);
}
else
{
result = currentFieldIndex == 0 ? source.OrderBy(sortField) : result.ThenBy(sortField);
}
}
return result;
}
}