I wanna create Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>
from list of SortingItems
dynamically.
I mean I wanna create the following expression:
entity => entity.OrderBy(c => c.Id).ThenBy(c => c.Name).ThenByDescending(c => c.LastName)
The following is my code :
[DataContract]
public class SortingItem
{
[DataMember]
public string PropertySelectorString { get; set; }
[DataMember]
public SortingDirectionsEnum SortingDirections { get; set; }
}
[DataContract]
public enum SortingDirectionsEnum
{
[EnumMember]
Descending = 0,
[EnumMember]
Ascending = 1
}
public Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> GetSortingFunc<TEntity>()
{
_entityType = typeof(TEntity);
_parameterExpression = Expression.Parameter(_entityType, "entity");
_iQueryableParameterExpression = Expression.Parameter(typeof(IQueryable<TEntity>), "f");
MethodInfo orderByMethodInfo = null;
Expression resultExpression = null;
foreach (SortingItem sortingItem in SortingItems)
{
MemberExpression memberExpression = GetLeftSide(sortingItem.PropertySelectorString, _entityType, _parameterExpression); // I'm dead sure about working this line
switch (sortingItem.SortingDirections)
{
case SortingDirectionsEnum.Descending:
orderByMethodInfo = typeof(Queryable).GetMethods().First(method => method.Name == "OrderBy" && method.GetParameters().Length == 2).MakeGenericMethod(_entityType, memberExpression.Type);
if (resultExpression != null)
orderByMethodInfo = typeof(Queryable).GetMethods().First(method => method.Name == "ThenBy" && method.GetParameters().Length == 2).MakeGenericMethod(_entityType, memberExpression.Type);
break;
case SortingDirectionsEnum.Ascending:
orderByMethodInfo = typeof(Queryable).GetMethods().First(method => method.Name == "OrderByDescending" && method.GetParameters().Length == 2).MakeGenericMethod(_entityType, memberExpression.Type);
if (resultExpression != null)
orderByMethodInfo = typeof(Queryable).GetMethods().First(method => method.Name == "ThenByDescending" && method.GetParameters().Length == 2).MakeGenericMethod(_entityType, memberExpression.Type);
break;
}
MethodCallExpression methodCallExpression;
if (resultExpression != null)
// Exception
// An unhandled exception of type 'System.ArgumentException' occurred in System.Core.dll
// Additional information: Incorrect number of arguments supplied for call to method 'System.Linq.IOrderedQueryable`1[ConsoleApplication1.User] ThenBy[User,Int32](System.Linq.IOrderedQueryable`1[ConsoleApplication1.User], System.Linq.Expressions.Expression`1[System.Func`2[ConsoleApplication1.User,System.Int32]])'
methodCallExpression = Expression.Call(orderByMethodInfo, _iQueryableParameterExpression, resultExpression, Expression.Lambda(memberExpression, _parameterExpression));
else
methodCallExpression = Expression.Call(orderByMethodInfo, _iQueryableParameterExpression, Expression.Lambda(memberExpression, _parameterExpression));
resultExpression = Expression.Lambda(methodCallExpression, _iQueryableParameterExpression);
}
Expression<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>> lambdaExpression = Expression.Lambda<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>>(resultExpression, _parameterExpression);
return lambdaExpression.Compile();
}
It's OK to create {f.OrderBy(entity => entity.Id)}
or {f.ThenBy(entity => entity.Name)}
seperately, but I get exception at the following line
methodCallExpression = Expression.Call(orderByMethodInfo, _iQueryableParameterExpression, resultExpression, Expression.Lambda(memberExpression, _parameterExpression));
How should I use Expression.Call
to combine {f.OrderBy(entity => entity.Id)}
with {f.ThenBy(entity => entity.Name)}
, .... ?
I suggest you not to write such code, as it's hard to read. I've had to maintain those monsters in the past.
If you're actually interested in the solution, you can download DynamicLINQ, and then your query will be as:
public string GetSortCriteria(this SortingItem item){
return string.Format("{0} {1}", item.PropertySelectorString,
item.SortingDirections == SortingDirectionsEnum.Descending ?
"DESC" : "ASC");
}
// later:
var mergedSortCriteria= string.Join(",",
SortingItems.Select(item => item.GetSortCriteria());
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> myFunc =
source => source.OrderBy("id " + mergedSortCriteria);
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