From ed6f33a84b0b6f5b264752ea0fe6577bcf7f2cd8 Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Fri, 27 Dec 2024 14:17:33 +0500 Subject: [PATCH] =?UTF-8?q?=D0=A3=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B4=D1=83=D0=B1=D0=BB=D0=B8=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D0=B5=20EFExtensionsSortBy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Extensions/EFExtensionsSortBy.cs | 159 +++++++----------- 1 file changed, 61 insertions(+), 98 deletions(-) diff --git a/DD.Persistence.Repository/Extensions/EFExtensionsSortBy.cs b/DD.Persistence.Repository/Extensions/EFExtensionsSortBy.cs index bdfc8a2..bed529e 100644 --- a/DD.Persistence.Repository/Extensions/EFExtensionsSortBy.cs +++ b/DD.Persistence.Repository/Extensions/EFExtensionsSortBy.cs @@ -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> 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> 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 /// Запрос с примененной сортировкой public static IOrderedQueryable SortBy( this IQueryable query, + Func> 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; - } - - /// - /// Добавить в запрос дополнительную сортировку по возрастанию или убыванию. - /// - /// - /// - /// - /// Свойство сортировки. - /// Состоит из названия свойства (в любом регистре) - /// и опционально указания направления сортировки "asc" или "desc" - /// - /// - /// var query = query("Date desc"); - /// - /// Запрос с примененной сортировкой - public static IOrderedQueryable ThenSortBy( - this IOrderedQueryable 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 /// Запрос с примененной сортировкой public static IOrderedQueryable SortBy( this IQueryable query, + Func> 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 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)genericMethod - .Invoke(genericMethod, [query, lambdaExpression])!; - return newQuery; - } + Tuple order = orderMethod + .Invoke(rootType, type, rootTypeAccessor); + orderByAscending = order.Item1; + orderByDescending = order.Item2; - /// - /// Добавить в запрос дополнительную сортировку по возрастанию или убыванию - /// - /// - /// - /// Название свойства (в любом регистре) - /// Сортировать по убыванию - /// Запрос с примененной сортировкой - public static IOrderedQueryable ThenSortBy( - this IOrderedQueryable 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 -- 2.45.2