#652 Устранить дублирование кода в файле persistence\Persistence.Repository\Extensions\EFExtensionsSortBy.cs (метод ThenSortBy) #18
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user