After using Linq To SQL queries, I was quickly confronted to sort my data with a string expression provided, for example, by a gridview when a user require it. At this moment, I understood that the strongly typed system used with Linq cannot help me for this task… Understanding the fact that allowing a string expression representing an object property is contrary to Linq purpose, I began to search with our best friend “Google” a soluce to resolve quickly my problem. But the best that I can obtain was a “switch case solution” which, according to the string property name, build the linq query sort filter with the associated object property. Immediatly, I guess my switch case code with 8-10 columns… No…
So, I started to write an extended method “OrderBy” allowing to take a string sort expression. Here the result.
/// <summary>
/// Extends method which allow to sort by string field name.
/// Allow to use a relative object definition for sorting (ex:LinkedObject.FieldsName1)
/// </summary>
/// <typeparam name=”TEntity”>Current Object type for query</typeparam>
/// <param name=”source”>list of defined object</param>
/// <param name=”sortExpression”>string name of the field we want to sort by</param>
/// <returns>Query sorted by sortExpression</returns>
public static IQueryable<TEntity> OrderBy<TEntity>(
this IQueryable<TEntity> source, string sortExpression) where TEntity : class
{
var type = typeof(TEntity);
// Remember that for ascending order GridView just returns the column name and
// for descending it returns column name followed by DESC keyword
// Therefore we need to examine the sortExpression and separate out Column Name and
// order (ASC/DESC)
string[] expressionParts = sortExpression.Split(‘ ‘); // Assuming sortExpression is like [ColumnName DESC] or [ColumnName]
string orderByProperty = expressionParts[0];
string sortDirection = “ASC”;
string methodName = “OrderBy”;
//if sortDirection is descending
if (expressionParts.Length > 1 && expressionParts[1] == “DESC”)
{
sortDirection = “Descending”;
methodName += sortDirection; // Add sort direction at the end of Method name
}
MethodCallExpression resultExp = null;
if (!orderByProperty.Contains(“.”))
{
var property = type.GetProperty(orderByProperty);
var parameter = Expression.Parameter(type, “p”);
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExp = Expression.Lambda(propertyAccess, parameter);
resultExp = Expression.Call(typeof(Queryable), methodName,
new Type[] { type, property.PropertyType },
source.Expression, Expression.Quote(orderByExp));
}
else
{
Type relationType = type.GetProperty(orderByProperty.Split(‘.’)[0]).PropertyType;
PropertyInfo relationProperty = type.GetProperty(orderByProperty.Split(‘.’)[0]);
PropertyInfo relationProperty2 = relationType.GetProperty(orderByProperty.Split(‘.’)[1]);
var parameter = Expression.Parameter(type, “p”);
var propertyAccess = Expression.MakeMemberAccess(parameter, relationProperty);
var propertyAccess2 = Expression.MakeMemberAccess(propertyAccess, relationProperty2);
var orderByExp = Expression.Lambda(propertyAccess2, parameter);
resultExp = Expression.Call(typeof(Queryable), methodName,
new Type[] { type, relationProperty2.PropertyType },
source.Expression, Expression.Quote(orderByExp));
}
return source.Provider.CreateQuery<TEntity>(resultExp);
}
/// <summary>
/// Allow to add another sorting on a query with a string representation of the field to sort by.
/// </summary>
/// <typeparam name=”TEntity”>Current Object type for query</typeparam>
/// <param name=”source”>list of defined object</param>
/// <param name=”sortExpression”>string name of the field we want to sort by</param>
/// <returns>Query sorted by sortExpression</returns>
public static IOrderedQueryable<TEntity> ThenBy<TEntity>(
this IOrderedQueryable<TEntity> source, string sortExpression) where TEntity : class
{
var type = typeof(TEntity);
// Remember that for ascending order GridView just returns the column name and
// for descending it returns column name followed by DESC keyword
// Therefore we need to examine the sortExpression and separate out Column Name and
// order (ASC/DESC)
string[] expressionParts = sortExpression.Split(‘ ‘); // Assuming sortExpression is like [ColumnName DESC] or [ColumnName]
string orderByProperty = expressionParts[0];
string sortDirection = “ASC”;
string methodName = “ThenBy”;
//if sortDirection is descending
if (expressionParts.Length > 1 && expressionParts[1] == “DESC”)
{
sortDirection = “Descending”;
methodName += sortDirection; // Add sort direction at the end of Method name
}
MethodCallExpression resultExp = null;
if (!orderByProperty.Contains(“.”))
{
var property = type.GetProperty(orderByProperty);
var parameter = Expression.Parameter(type, “p”);
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExp = Expression.Lambda(propertyAccess, parameter);
resultExp = Expression.Call(typeof(Queryable), methodName,
new Type[] { type, property.PropertyType },
source.Expression, Expression.Quote(orderByExp));
}
else
{
Type relationType = type.GetProperty(orderByProperty.Split(‘.’)[0]).PropertyType;
PropertyInfo relationProperty = type.GetProperty(orderByProperty.Split(‘.’)[0]);
PropertyInfo relationProperty2 = relationType.GetProperty(orderByProperty.Split(‘.’)[1]);
var parameter = Expression.Parameter(type, “p”);
var propertyAccess = Expression.MakeMemberAccess(parameter, relationProperty);
var propertyAccess2 = Expression.MakeMemberAccess(propertyAccess, relationProperty2);
var orderByExp = Expression.Lambda(propertyAccess2, parameter);
resultExp = Expression.Call(typeof(Queryable), methodName,
new Type[] { type, relationProperty2.PropertyType },
source.Expression, Expression.Quote(orderByExp));
}
return (IOrderedQueryable<TEntity>)source.Provider.CreateQuery<TEntity>(resultExp);
}
great job
Thanks for this, very helpful.
I used SortDirection, which comes from the GridView event. I changed your code to have the following signature:
public static IQueryable OrderBy(
this IQueryable source,
string sortExpression,
SortDirection sortDirection) where TEntity : class
Great!! this made my life simpler. Thanks.
Thanks helped a lot.
You are amazing! This is no where to be found except here… Thank you so much. You solved my problem!!!
Oh my goodness! Incredible article dude! Many thanks, However I am having troubles with your RSS.
I don’t understand the reason why I am unable to subscribe to it. Is there anybody else getting the same RSS problems? Anybody who knows the solution can you kindly respond? Thanks!!
Indeed, this little workaround seems to help many people 🙂
Regarding your subscription, you have to click the follow button in the top bar. In your wordpress reader, you will find a subscription action on the right menu and click edit. select the blogs that you want to follow.
Is that what you wanted to do ?