3
\$\begingroup\$

Here is my OrderBy method which includes concatenated column names. Can this be achieved more efficiently?

public static IQueryable<T> Sort<T>(this IQueryable<T> query, List<SortationDto> sortations)
 where T : BaseEntity
{
 sortations.ForEach(s =>
 {
 Expression value = null;
 ParameterExpression parameter = Expression.Parameter(query.ElementType, "item");
 // if sortation is a concatenation of two columns
 if (s.Concatenated.Count > 0)
 {
 Expression concat = null;
 s.Concatenated.ForEach(c =>
 {
 //get first property
 value = c.Column.Split('.').Aggregate((Expression)parameter, Expression.PropertyOrField);
 //if first property add as initial property
 if (concat == null)
 {
 concat = value;
 }
 else //else concatenate with first property
 {
 MethodInfo concatMethod = typeof(String).GetMethod("Concat", new Type[] { typeof(string), typeof(string), typeof(string) });
 value = Expression.Call(concatMethod, concat, Expression.Constant(" "), value);
 }
 });
 }
 else //else use one and only property
 {
 value = s.Column.Split('.').Aggregate((Expression)parameter, Expression.PropertyOrField);
 }
 //build lambda expression
 LambdaExpression predicate = Expression.Lambda(value, parameter);
 //define orderby method name based on current iteration of sortations
 string methodName = (sortations.IndexOf(s) == 0 ? "Order" : "Then") + (s.Direction == "asc" ? "By" : "ByDescending");
 //call method
 MethodCallExpression orderBy = Expression.Call(typeof(Queryable), methodName, new Type[] { query.ElementType, value.Type }, query.Expression, Expression.Quote(predicate));
 //add final expression to query
 query = query.Provider.CreateQuery<T>(orderBy);
 });
 return query;
}
asked Feb 21, 2016 at 10:53
\$\endgroup\$
2
  • \$\begingroup\$ What's the point of sorting concatenations when you're already supporting sorting by multiple columns? \$\endgroup\$ Commented Feb 21, 2016 at 15:26
  • \$\begingroup\$ Good point! I'll rework this method. \$\endgroup\$ Commented Feb 21, 2016 at 16:12

2 Answers 2

1
\$\begingroup\$

Removed unnecessary concatenation.

public static IQueryable<T> Sort<T>(this IQueryable<T> query, List<SortationDto> sortations)
 where T : BaseEntity
{
 List<SortationDto> combined = sortations.Where(s => s.Concatenated.Count == 0).Union(sortations.SelectMany(so => so.Concatenated)).ToList();
 combined.ForEach(s =>
 {
 ParameterExpression parameter = Expression.Parameter(query.ElementType, "item");
 Expression value = s.Column.Split('.').Aggregate((Expression)parameter, Expression.PropertyOrField);
 LambdaExpression predicate = Expression.Lambda(value, parameter);
 string methodName = (combined.IndexOf(s) == 0 ? "Order" : "Then") + (s.Direction == "asc" ? "By" : "ByDescending");
 MethodCallExpression orderBy = Expression.Call(typeof(Queryable), methodName, new Type[] { query.ElementType, value.Type }, query.Expression, Expression.Quote(predicate)); 
 query = query.Provider.CreateQuery<T>(orderBy);
 });
 return query;
}
answered Feb 21, 2016 at 17:35
\$\endgroup\$
0
\$\begingroup\$

Thanks for sharing your code! Works like a charm. Ended up using it with some adjustments and the extension method below. I pass the Sort objects in so that any parsing is done outside (separate the concern a bit).

public static IQueryable<TEntity> ApplySort<TEntity>(this IQueryable<TEntity> query, params Sort[] sorts)
 {
 if (sorts == null)
 return query;
 var applicableSorts = sorts.Where(s => s != null);
 if (!applicableSorts.Any())
 return query;
 applicableSorts
 .Select((item, index) => new { Index = index, item.PropertyName, item.Direction })
 .ToList()
 .ForEach(sort =>
 {
 ParameterExpression parameterExpression = Expression.Parameter(query.ElementType, "entity");
 var propertyExpression = Expression.Property(parameterExpression, sort.PropertyName);
 var sortPredicate = Expression.Lambda(propertyExpression, parameterExpression);
 string methodName = (sort.Index == 0 ? "Order" : "Then") + (sort.Direction == OrderDirection.Ascending ? "By" : "ByDescending");
 MethodCallExpression orderBy = Expression.Call(typeof(Queryable), methodName, new Type[] { query.ElementType, propertyExpression.Type }, query.Expression, Expression.Quote(sortPredicate));
 query = query.Provider.CreateQuery<TEntity>(orderBy);
 });
 return query;
 }
answered Mar 21, 2019 at 11:08
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.