\$\begingroup\$
\$\endgroup\$
2
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;
}
Sean ThorburnSean Thorburn
asked Feb 21, 2016 at 10:53
-
\$\begingroup\$ What's the point of sorting concatenations when you're already supporting sorting by multiple columns? \$\endgroup\$svick– svick2016年02月21日 15:26:44 +00:00Commented Feb 21, 2016 at 15:26
-
\$\begingroup\$ Good point! I'll rework this method. \$\endgroup\$Sean Thorburn– Sean Thorburn2016年02月21日 16:12:11 +00:00Commented Feb 21, 2016 at 16:12
2 Answers 2
\$\begingroup\$
\$\endgroup\$
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
\$\begingroup\$
\$\endgroup\$
0
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
lang-cs