Устранить дублирование EFExtensionsSortBy
All checks were successful
Unit tests / test (push) Successful in 1m27s

This commit is contained in:
Roman Efremov 2024-12-27 14:17:33 +05:00
parent 01898e84f6
commit ed6f33a84b

View File

@ -6,7 +6,7 @@ namespace DD.Persistence.Repository.Extensions;
public static class EFExtensionsSortBy
{
struct TypeAccessor
public struct TypeAccessor
{
public LambdaExpression KeySelector { get; set; }
public MethodInfo OrderBy { get; set; }
@ -26,6 +26,42 @@ public static class EFExtensionsSortBy
private static readonly MethodInfo methodThenByDescending = GetExtOrderMethod("ThenByDescending");
public static Func<Type, Type?, TypeAccessor?, Tuple<MethodInfo, MethodInfo>> sortOrder =
(Type rootType, Type? type, TypeAccessor? accessor) =>
{
if (type is null && accessor.HasValue)
{
var accessorValue = accessor.Value;
return Tuple.Create(
accessorValue.OrderBy,
accessorValue.OrderByDescending
);
}
return Tuple.Create(
methodOrderBy.MakeGenericMethod(rootType, type!),
methodOrderByDescending.MakeGenericMethod(rootType, type!)
);
};
public static Func<Type, Type?, TypeAccessor?, Tuple<MethodInfo, MethodInfo>> thenSortOrder =
(Type rootType, Type? type, TypeAccessor? accessor) =>
{
if (type is null && accessor.HasValue)
{
var accessorValue = accessor.Value;
return Tuple.Create(
accessorValue.ThenBy,
accessorValue.ThenByDescending
);
}
return Tuple.Create(
methodThenBy.MakeGenericMethod(rootType, type!),
methodThenByDescending.MakeGenericMethod(rootType, type!)
);
};
private static MethodInfo GetExtOrderMethod(string methodName)
=> typeof(Queryable)
.GetMethods()
@ -83,10 +119,11 @@ public static class EFExtensionsSortBy
var sortEnum = propertySorts.GetEnumerator();
sortEnum.MoveNext();
var orderedQuery = query.SortBy(sortEnum.Current);
var orderedQuery = query.SortBy(sortOrder, sortEnum.Current);
while (sortEnum.MoveNext())
orderedQuery = orderedQuery.ThenSortBy(sortEnum.Current);
orderedQuery = orderedQuery.SortBy(thenSortOrder, sortEnum.Current);
return orderedQuery;
}
@ -108,39 +145,14 @@ public static class EFExtensionsSortBy
/// <returns>Запрос с примененной сортировкой</returns>
public static IOrderedQueryable<TSource> SortBy<TSource>(
this IQueryable<TSource> query,
Func<Type, Type?, TypeAccessor?, Tuple<MethodInfo, MethodInfo>> orderMethod,
string propertySort)
{
var parts = propertySort.Split(" ", 2, StringSplitOptions.RemoveEmptyEntries);
var isDesc = parts.Length >= 2 && parts[1].ToLower().Trim() == "desc";
var propertyName = parts[0];
var newQuery = query.SortBy(propertyName, isDesc);
return newQuery;
}
/// <summary>
/// Добавить в запрос дополнительную сортировку по возрастанию или убыванию.
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="query"></param>
/// <param name="propertySort">
/// Свойство сортировки.
/// Состоит из названия свойства (в любом регистре)
/// и опционально указания направления сортировки "asc" или "desc"
/// </param>
/// <example>
/// var query = query("Date desc");
/// </example>
/// <returns>Запрос с примененной сортировкой</returns>
public static IOrderedQueryable<TSource> ThenSortBy<TSource>(
this IOrderedQueryable<TSource> query,
string propertySort)
{
var parts = propertySort.Split(" ", 2, StringSplitOptions.RemoveEmptyEntries);
var isDesc = parts.Length >= 2 && parts[1].ToLower().Trim() == "desc";
var propertyName = parts[0];
var newQuery = query.ThenSortBy(propertyName, isDesc);
var newQuery = query.SortBy(orderMethod, propertyName, isDesc);
return newQuery;
}
@ -154,25 +166,27 @@ public static class EFExtensionsSortBy
/// <returns>Запрос с примененной сортировкой</returns>
public static IOrderedQueryable<TSource> SortBy<TSource>(
this IQueryable<TSource> query,
Func<Type, Type?, TypeAccessor?, Tuple<MethodInfo, MethodInfo>> orderMethod,
string propertyName,
bool isDesc)
{
Type rootType = typeof(TSource);
var typePropSelector = TypePropSelectors.GetOrAdd(rootType, MakeTypeAccessors);
var propertyNameLower = propertyName.ToLower();
MethodInfo orderByDescending;
MethodInfo orderByAscending;
TypeAccessor? rootTypeAccessor = null;
Type? type = null;
LambdaExpression? lambdaExpression = null;
if (propertyName.Contains('.'))
const string Separator = ".";
if (propertyName.Contains(Separator))
{
Type type = rootType;
type = rootType;
ParameterExpression rootExpression = Expression.Parameter(rootType, "x");
Expression expr = rootExpression;
var propertyPath = propertyName.Split(".", StringSplitOptions.RemoveEmptyEntries);
var propertyPath = propertyName.Split(Separator, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < propertyPath.Length; i++)
{
@ -184,75 +198,24 @@ public static class EFExtensionsSortBy
Type delegateType = typeof(Func<,>).MakeGenericType(rootType, type);
lambdaExpression = Expression.Lambda(delegateType, expr, rootExpression);
orderByAscending = methodOrderBy.MakeGenericMethod(rootType, type);
orderByDescending = methodOrderByDescending.MakeGenericMethod(rootType, type);
Tuple<MethodInfo, MethodInfo> order = orderMethod
.Invoke(rootType, type, null);
orderByAscending = order.Item1;
orderByDescending = order.Item2;
}
else
{
var rootTypeAccessor = typePropSelector[propertyNameLower];
orderByAscending = rootTypeAccessor.OrderBy;
orderByDescending = rootTypeAccessor.OrderByDescending;
lambdaExpression = rootTypeAccessor.KeySelector;
}
var typePropSelector = TypePropSelectors.GetOrAdd(rootType, MakeTypeAccessors);
var propertyNameLower = propertyName.ToLower();
var genericMethod = isDesc
? orderByDescending
: orderByAscending;
rootTypeAccessor = typePropSelector[propertyNameLower];
var newQuery = (IOrderedQueryable<TSource>)genericMethod
.Invoke(genericMethod, [query, lambdaExpression])!;
return newQuery;
}
Tuple<MethodInfo, MethodInfo> order = orderMethod
.Invoke(rootType, type, rootTypeAccessor);
orderByAscending = order.Item1;
orderByDescending = order.Item2;
/// <summary>
/// Добавить в запрос дополнительную сортировку по возрастанию или убыванию
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="query"></param>
/// <param name="propertyName">Название свойства (в любом регистре)</param>
/// <param name="isDesc">Сортировать по убыванию</param>
/// <returns>Запрос с примененной сортировкой</returns>
public static IOrderedQueryable<TSource> ThenSortBy<TSource>(
this IOrderedQueryable<TSource> query,
string propertyName,
bool isDesc)
{
Type rootType = typeof(TSource);
var typePropSelector = TypePropSelectors.GetOrAdd(rootType, MakeTypeAccessors);
var propertyNameLower = propertyName.ToLower();
MethodInfo orderByDescending;
MethodInfo orderByAscending;
LambdaExpression? lambdaExpression = null;
if (propertyName.Contains('.'))
{
Type type = rootType;
ParameterExpression rootExpression = Expression.Parameter(rootType, "x");
Expression expr = rootExpression;
var propertyPath = propertyName.Split(".", StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < propertyPath.Length; i++)
{
PropertyInfo pi = type.GetProperty(propertyPath[i])!;
expr = Expression.Property(expr, pi);
type = pi.PropertyType;
}
Type delegateType = typeof(Func<,>).MakeGenericType(rootType, type);
lambdaExpression = Expression.Lambda(delegateType, expr, rootExpression);
orderByAscending = methodThenBy.MakeGenericMethod(rootType, type);
orderByDescending = methodThenByDescending.MakeGenericMethod(rootType, type);
}
else
{
var rootTypeAccessor = typePropSelector[propertyNameLower];
orderByAscending = rootTypeAccessor.ThenBy;
orderByDescending = rootTypeAccessor.ThenByDescending;
lambdaExpression = rootTypeAccessor.KeySelector;
lambdaExpression = rootTypeAccessor.Value.KeySelector;
}
var genericMethod = isDesc