-
Hi there, I'm currently using AutoFilterer for paging and filtering and would like to get sorting working. While working on implementing this, I noticed that Sort and SortBy is only supported on a single field. Is it possible to sort on multiple fields without writing custom Expressions? |
Beta Was this translation helpful? Give feedback.
Answered by
enisn
Feb 22, 2023
Replies: 1 comment 1 reply
-
It's a good point. Filtering multiple fields in a single field is not Open API Specs friendly and it's not supported by AutoFilterer by default. But I can share an example code that helps you to achieve this goal.
public class MultipleSortingFilterBase : PaginationFilterBase
{
public override IOrderedQueryable<TSource> ApplyOrder<TSource>(IQueryable<TSource> source)
{
// books?sort=title asc,totalPage desc
var sortings = this.Sort.Split(',');
var query = source;
for (int i = 0; i < sortings.Length; i++)
{
if (i == 0)
{
query = ApplyOrderBy(query, sortings[i].Split(' ').First(), sortings[i].EndsWith("desc"));
}
else
{
query = ApplyThenBy(query as IOrderedQueryable<TSource>, sortings[i].Split(' ').First(), sortings[i].EndsWith("desc"));
}
}
return query as IOrderedQueryable<TSource>;
}
private static readonly MethodInfo orderBy = typeof(Queryable).GetMethods().First(x => x.Name == nameof(Queryable.OrderBy));
private static readonly MethodInfo orderByDescending = typeof(Queryable).GetMethods().First(x => x.Name == nameof(Queryable.OrderByDescending));
private static readonly MethodInfo thenBy = typeof(Queryable).GetMethods().First(x => x.Name == nameof(Queryable.ThenBy));
private static readonly MethodInfo thenByDescending = typeof(Queryable).GetMethods().First(x => x.Name == nameof(Queryable.ThenByDescending));
private IOrderedQueryable<TSource> ApplyOrderBy<TSource>(IQueryable<TSource> source, string propertyName, bool descending)
{
var parameter = Expression.Parameter(typeof(TSource), "o");
var property = GetMemberExpression(parameter, propertyName);
var lambda = Expression.Lambda(property, parameter);
if (descending)
{
return orderByDescending.MakeGenericMethod(typeof(TSource), property.Type)
.Invoke(null, parameters: new object[] { source, lambda }) as IOrderedQueryable<TSource>;
}
return orderBy.MakeGenericMethod(typeof(TSource), property.Type)
.Invoke(null, parameters: new object[] { source, lambda }) as IOrderedQueryable<TSource>;
}
private IOrderedQueryable<TSource> ApplyThenBy<TSource>(IOrderedQueryable<TSource> source, string propertyName, bool descending)
{
var parameter = Expression.Parameter(typeof(TSource), "o");
var property = GetMemberExpression(parameter, propertyName);
var lambda = Expression.Lambda(property, parameter);
if (descending)
{
return thenByDescending.MakeGenericMethod(typeof(TSource), property.Type)
.Invoke(null, parameters: new object[] { source, lambda }) as IOrderedQueryable<TSource>;
}
return thenBy.MakeGenericMethod(typeof(TSource), property.Type)
.Invoke(null, parameters: new object[] { source, lambda }) as IOrderedQueryable<TSource>;
}
private static MemberExpression GetMemberExpression(Expression parameter, string name)
{
if (!name.Contains("."))
return Expression.Property(parameter, name);
var expression = parameter;
foreach (var item in name.Split('.'))
{
expression = GetMemberExpression(expression, item);
}
return expression as MemberExpression;
}
}
public class BookFilter : MultipleSortingFilterBase
{
// ...
} |
Beta Was this translation helpful? Give feedback.
1 reply
Answer selected by
AdamAdu3
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It's a good point. Filtering multiple fields in a single field is not Open API Specs friendly and it's not supported by AutoFilterer by default. But I can share an example code that helps you to achieve this goal.