我有一项服务,必须按升序或降序排序。为此,我收到两件事:排序顺序,必须在其上进行排序的列。 我尝试使用linq来实现这一点,以便可以直接使用EF Core对BD查询进行排序 警告:我可以对其进行排序的列可能包含子对象:property1.subProperty.subProperty
我发现了这个:
public static class IQueryableExtensions
{
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
return CallOrderedQueryable(query, "OrderBy", propertyName, comparer);
}
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
return CallOrderedQueryable(query, "OrderByDescending", propertyName, comparer);
}
public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
return CallOrderedQueryable(query, "ThenBy", propertyName, comparer);
}
public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
return CallOrderedQueryable(query, "ThenByDescending", propertyName, comparer);
}
/// <summary>
/// Builds the Queryable functions using a TSource property name.
/// </summary>
public static IOrderedQueryable<T> CallOrderedQueryable<T>(this IQueryable<T> query, string methodName, string propertyName,
IComparer<object> comparer = null)
{
var param = Expression.Parameter(typeof(T), "x");
var body = propertyName.Split('.').Aggregate<string, Expression>(param, Expression.PropertyOrField);
return comparer != null
? (IOrderedQueryable<T>)query.Provider.CreateQuery(
Expression.Call(
typeof(Queryable),
methodName,
new[] { typeof(T), body.Type },
query.Expression,
Expression.Lambda(body, param),
Expression.Constant(comparer)
)
)
: (IOrderedQueryable<T>)query.Provider.CreateQuery(
Expression.Call(
typeof(Queryable),
methodName,
new[] { typeof(T), body.Type },
query.Expression,
Expression.Lambda(body, param)
)
);
}
}
但是我想根据排序值(ASC或DESC)和属性值(property1或property1.subproperty或property1.subproperty.subsubproperty,...)动态调用正确的方法
答案 0 :(得分:0)
这可能会对您有所帮助。这也将为您提供可用于其他项目中动态排序的内容。
用于包含排序信息的类:
public class SortRequest
{
/// <summary>
/// What field/column to sort by
/// </summary>
public string Field { get; set; }
/// <summary>
/// Whether to sort by descending or not.
/// Defaults to false
/// </summary>
public bool SortDescending { get; set; } = false;
}//Cls
进行排序的类
public static class SortingExtensions
{
//------------------------------------------------------------------------//
/// <summary>
/// Sorts <paramref name="list"/> according to the details in <paramref name="sortRequestList"/>
/// </summary>
/// <typeparam name="T">The type of objects being sorted</typeparam>
/// <param name="list">The items to sort</param>
/// <param name="sortRequestList">List of fields to sort by</param>
/// <param name="getPropertySelectorLambda">Function to convert string field to a T property</param>
/// <returns>The same list with sorting appended to it</returns>
public static IEnumerable<T> AddSorting<T>(this IEnumerable<T> list, IEnumerable<SortRequest> sortRequestList, Func<string, Func<T, object>> getPropertySelectorLambda)
{
if (sortRequestList == null || !sortRequestList.Any() || list == null || !list.Any())
return list;
var isFirst = true;
foreach (var sr in sortRequestList)
{
Func<T, object> lmda = getPropertySelectorLambda(sr.Field);
list = list.AddSortLevel(sr.SortDescending, lmda, isFirst);
isFirst = false;
}//foreach
return list;
}//SortProducts
//------------------------------------------------------------------------//
/// <summary>
/// Adds a level of sorting to the linq queue
/// </summary>
/// <typeparam name="T">Type of objects being sorted</typeparam>
/// <param name="list">The Items being sorted</param>
/// <param name="sortDescending">What direction to sort</param>
/// <param name="propertySelectorLambda">Function dexcribing what property to sort on.</param>
/// <param name="isFirst">Is this the first item in the LINQ sort queue</param>
/// <returns>The same list with sorting appended to it</returns>
private static IOrderedEnumerable<T> AddSortLevel<T>(this IEnumerable<T> list, bool sortDescending, Func<T, object> propertySelectorLambda, bool isFirst)
{
if (isFirst)
list = FirstSortLevel(list, sortDescending, propertySelectorLambda);
else
list = NextSortLevel(list as IOrderedEnumerable<T>, sortDescending, propertySelectorLambda);
//Will definitely be IOrderedEnumerable here.
return list as IOrderedEnumerable<T>;
}//FirstSortLevel
//------------------------------------------------------------------------//
/// <summary>
/// Adds a level of sorting to the linq queue (OrderBy)
/// </summary>
/// <typeparam name="T">Type of objects being sorted</typeparam>
/// <param name="list">The Items being sorted</param>
/// <param name="sortDescending">What direction to sort</param>
/// <param name="propertySelectorLambda">Function dexcribing what property to sort on.</param>
/// <param name="isFirst">Is this the first item in the LINQ sort queue</param>
/// <returns>The same list with sorting appended to it</returns>
private static IOrderedEnumerable<T> FirstSortLevel<T>(this IEnumerable<T> list, bool sortDescending, Func<T, object> propertySelectorLambda)
{
if (sortDescending)
list = list.OrderByDescending(propertySelectorLambda);
else
list = list.OrderBy(propertySelectorLambda);
//Will definitely be IOrderedEnumerable here.
return list as IOrderedEnumerable<T>;
}//FirstSortLevel
//------------------------------------------------------------------------//
/// <summary>
/// Adds a level of sorting to the linq queue (ThenBy)
/// </summary>
/// <typeparam name="T">Type of objects being sorted</typeparam>
/// <param name="list">The Items being sorted</param>
/// <param name="sortDescending">What direction to sort</param>
/// <param name="propertySelectorLambda">Function dexcribing what property to sort on.</param>
/// <param name="isFirst">Is this the first item in the LINQ sort queue</param>
/// <returns>The same list with sorting appended to it</returns>
private static IOrderedEnumerable<T> NextSortLevel<T>(this IOrderedEnumerable<T> list, bool sortDescending, Func<T, object> propertySelectorLambda)
{
if (sortDescending)
list = list.ThenByDescending(propertySelectorLambda);
else
list = list.ThenBy(propertySelectorLambda);
return list;
}//NextSortLevel
//------------------------------------------------------------------------//
}//Cls
如何使用它: 您传递了sortRequest列表,每个列表都有您的属性名称和排序方向。
然后,getPropertySelectorLambda将为您提供排序中使用的表达式/函数。
以下是我使用的示例:
private Func<Nurse, object> GetSortingPropertySelectorLambda(string field)
{
return (field.CamelToPascal()) switch
{
nameof(Nurse.Id) => p => p.Id,
nameof(Nurse.PinNumber) => p => p.PinNumber,
nameof(Nurse.FirstName) => p => p.FirstName,
nameof(Nurse.LastName) => p => p.LastName,
nameof(Nurse.AddressLine1) => p => p.AddressLine1,
nameof(Nurse.AddressLine2) => p => p.AddressLine2,
nameof(Nurse.AddressLine3) => p => p.AddressLine3,
nameof(Nurse.AddressLine4) => p => p.AddressLine4,
nameof(Nurse.PhoneNumber) => p => p.PhoneNumber,
nameof(Nurse.PhoneNumber2) => p => p.PhoneNumber2,
nameof(Nurse.EmailAddress) => p => p.EmailAddress,
nameof(Nurse.DateOfBirth) => p => p.DateOfBirth,
nameof(Nurse.PayrollNumber) => p => p.PayrollNumber,
nameof(Nurse.Branch) => p => p.Branch.Name,
_ => p => p.Id,
};
}//GetSortingPropertySelectorLambda
您也可以根据sortRequest自己构建该表达式(就像您在上面所做的一样)。
之所以拥有“ FirstSortLevel”方法,是因为第一个排序必须为OrderBy,但随后的所有排序都必须为“ ThenBy”。
所以我们要做的就是创建/获取表达式,该表达式决定要过滤的属性。然后只需使用常规的LINQ进行排序(我们不会将这些查询构建为表达式)。
示例用法:
var sortedData = allData
.AddSorting(sortList, GetSortingPropertySelectorLambda)
.ToList();