分页排序和多条件查询

This commit is contained in:
administrator committed 2024-04-09 22:56:19 +08:00
1 parent 62a8b7f569
commit 6fef1a9ea0
7 files changed
+161 -16

No files matched your search

@@ -0,0 +1,78 @@
using HelloShop.ServiceDefaults.Constants;
using HelloShop.ServiceDefaults.Models.Paging;
using System.Linq.Expressions;
using System.Reflection;
namespace HelloShop.ServiceDefaults.Extensions;
public static class QueryableExtensions
{
public static IQueryable<TEntity> SortBy<TEntity>(this IQueryable<TEntity> query, string? orderBy = null)
{
PropertyInfo[] properties = typeof(TEntity).GetProperties();
IOrderedQueryable<TEntity>? orderedQueryable = null;
if (!string.IsNullOrWhiteSpace(orderBy))
{
// Convert expressions of the form field1 desc,field2 asc
string[] orderBySubs = orderBy.Split(',');
foreach (var orderBySub in orderBySubs)
{
string[] orderByParts = orderBySub.Trim().Split(' ');
if (orderByParts.Length >= 1)
{
string propertyName = PascalCaseNamingPolicy.PascalCase.ConvertName(orderByParts[0]);
bool ascending = orderByParts.Length == 1 || (orderByParts.Length == 2 && orderByParts[1].Equals("asc", StringComparison.OrdinalIgnoreCase));
if (properties.Any(x => x.Name == propertyName))
{
if (ascending)
{
orderedQueryable = orderedQueryable is null ? query.OrderBy(propertyName) : orderedQueryable.ThenBy(propertyName);
}
else
{
orderedQueryable = orderedQueryable is null ? query.OrderByDescending(propertyName) : orderedQueryable.ThenByDescending(propertyName);
}
}
}
}
}
if (orderedQueryable is null)
{
string defaultPropertyName = properties.Any(x => x.Name == EntityConnstants.DefaultKey) ? EntityConnstants.DefaultKey : properties.First().Name;
orderedQueryable = query.OrderByDescending(defaultPropertyName);
}
return orderedQueryable;
}
public static IQueryable<TEntity> PageBy<TEntity>(this IQueryable<TEntity> query, PagedRequest pagedRequest)
{
return query.Skip((pagedRequest.PageNumber - 1) * pagedRequest.PageSize).Take(pagedRequest.PageSize);
}
public static IQueryable<TEntity> SortAndPageBy<TEntity>(this IQueryable<TEntity> query, PagedAndSortedRequest? pagedAndSortedRequest = null)
{
pagedAndSortedRequest ??= new PagedAndSortedRequest { PageNumber = 1, PageSize = PagingConstants.DefaultPageSize };
return query.SortBy(pagedAndSortedRequest.OrderBy).PageBy(pagedAndSortedRequest);
}
public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool condition, Expression<Func<TSource, bool>> predicate)
{
return condition ? source.Where(predicate) : source;
}
public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool condition, Expression<Func<TSource, int, bool>> predicate)
{
return condition ? source.Where(predicate) : source;
}
}
@@ -0,0 +1,44 @@
using System.Collections.Concurrent;
using System.Linq.Expressions;
namespace HelloShop.ServiceDefaults.Extensions;
public static class QueryableOrderByExtensions
{
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName) => OrderingHelper<T>.OrderBy(source, propertyName);
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string propertyName) => OrderingHelper<T>.OrderByDescending(source, propertyName);
public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string propertyName) => OrderingHelper<T>.ThenBy(source, propertyName);
public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string propertyName) => OrderingHelper<T>.ThenByDescending(source, propertyName);
private static class OrderingHelper<TSource>
{
private static readonly ConcurrentDictionary<string, LambdaExpression> cached = new();
public static IOrderedQueryable<TSource> OrderBy(IQueryable<TSource> source, string propertyName) => Queryable.OrderBy(source, (dynamic)CreateLambdaExpression(propertyName));
public static IOrderedQueryable<TSource> OrderByDescending(IQueryable<TSource> source, string propertyName) => Queryable.OrderByDescending(source, (dynamic)CreateLambdaExpression(propertyName));
public static IOrderedQueryable<TSource> ThenBy(IOrderedQueryable<TSource> source, string propertyName) => Queryable.ThenBy(source, (dynamic)CreateLambdaExpression(propertyName));
public static IOrderedQueryable<TSource> ThenByDescending(IOrderedQueryable<TSource> source, string propertyName) => Queryable.ThenByDescending(source, (dynamic)CreateLambdaExpression(propertyName));
private static LambdaExpression CreateLambdaExpression(string propertyName)
{
if (cached.TryGetValue(propertyName, out LambdaExpression? value))
{
return value;
}
var parameter = Expression.Parameter(typeof(TSource));
var body = Expression.Property(parameter, propertyName);
var keySelector = Expression.Lambda(body, parameter);
cached[propertyName] = keySelector;
return keySelector;
}
}
}
@@ -0,0 +1,10 @@
using System.Text.Json;
namespace HelloShop.ServiceDefaults;
public class PascalCaseNamingPolicy : JsonNamingPolicy
{
public static PascalCaseNamingPolicy PascalCase { get; } = new PascalCaseNamingPolicy();
public override string ConvertName(string name) => string.Concat(char.ToUpper(name[0]), name[1..]);
}
@@ -2,5 +2,5 @@
public class PagedAndSortedRequest : PagedRequest
{
public IEnumerable<SortingOrder>? Sorts { get; init; }
}
public string? OrderBy { get; init; }
}
@@ -1,8 +0,0 @@
namespace HelloShop.ServiceDefaults.Models.Paging;
public class SortingOrder
{
public required string PropertyName { get; init; }
public bool Ascending { get; init; }
}