83 lines
2.9 KiB
C#
83 lines
2.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Linq.Expressions;
|
|
using System.Reflection;
|
|
using System.Threading.Tasks;
|
|
using Generic.Contracts.Generics;
|
|
|
|
namespace Generic.Services;
|
|
|
|
public static class SortExt
|
|
{
|
|
public static IQueryable<T> ApplySimpleSort<T>(this IQueryable<T> query, SortModel sortModel)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(sortModel?.SortBy))
|
|
return query;
|
|
|
|
return ApplySortInternal(query, new[] { sortModel });
|
|
}
|
|
|
|
public static IQueryable<T> ApplyComplexSort<T>(this IQueryable<T> query, IEnumerable<SortModel> sortModels)
|
|
{
|
|
var models = sortModels?.Where(x => !string.IsNullOrWhiteSpace(x.SortBy)).ToList();
|
|
if (models == null || !models.Any())
|
|
return query;
|
|
|
|
return ApplySortInternal(query, models);
|
|
}
|
|
|
|
private static IQueryable<T> ApplySortInternal<T>(IQueryable<T> query, IEnumerable<SortModel> sortModels)
|
|
{
|
|
var first = true;
|
|
IOrderedQueryable<T> orderedQuery = null;
|
|
|
|
foreach (var model in sortModels)
|
|
{
|
|
var propertyInfo = typeof(T).GetProperty(
|
|
model.SortBy,
|
|
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance
|
|
);
|
|
|
|
if (propertyInfo == null)
|
|
{
|
|
// Decide whether to throw or ignore. For now, letting it throw or we could ignore.
|
|
// Original code threw exception, so we will throw to be safe/consistent.
|
|
throw new ArgumentException(
|
|
$"No property '{model.SortBy}' on type '{typeof(T).Name}'"
|
|
);
|
|
}
|
|
|
|
var parameter = Expression.Parameter(typeof(T), "x");
|
|
var property = Expression.Property(parameter, propertyInfo);
|
|
var lambda = Expression.Lambda(property, parameter);
|
|
|
|
string methodName = "";
|
|
|
|
if (first)
|
|
{
|
|
methodName = model.SortDirection == SortDir.Descending ? "OrderByDescending" : "OrderBy";
|
|
|
|
var method = typeof(Queryable).GetMethods()
|
|
.First(m => m.Name == methodName && m.GetParameters().Length == 2)
|
|
.MakeGenericMethod(typeof(T), propertyInfo.PropertyType);
|
|
|
|
orderedQuery = (IOrderedQueryable<T>)method.Invoke(null, new object[] { query, lambda });
|
|
first = false;
|
|
}
|
|
else
|
|
{
|
|
methodName = model.SortDirection == SortDir.Descending ? "ThenByDescending" : "ThenBy";
|
|
|
|
var method = typeof(Queryable).GetMethods()
|
|
.First(m => m.Name == methodName && m.GetParameters().Length == 2)
|
|
.MakeGenericMethod(typeof(T), propertyInfo.PropertyType);
|
|
|
|
orderedQuery = (IOrderedQueryable<T>)method.Invoke(null, new object[] { orderedQuery, lambda });
|
|
}
|
|
}
|
|
|
|
return orderedQuery ?? query;
|
|
}
|
|
}
|