Files
Generic.CL/Services/SortExt.cs
T

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;
}
}