public enum OrderByStatus
{
ASC,
DESC
}
public static class OrderByHelper
{
public static IOrderedQueryable<T> OrderIf<T, TKey>(this IQueryable<T> source, Expression<Func<T, TKey>> order, OrderByStatus status, bool isEnable)
{
IOrderedQueryable<T> result = null;
if (source != null && order != null)
{
if (isEnable)
{
//已有OrderBy
if (source.ContainsOrderBy())
{
if (status == OrderByStatus.ASC)
result = (source as IOrderedQueryable<T>).ThenBy(order);
else
result = (source as IOrderedQueryable<T>).ThenByDescending(order);
}
else //未有 OrderBy
{
if (status == OrderByStatus.ASC)
result = source.OrderBy(order);
else
result = source.OrderByDescending(order);
}
}
else result = (source as IOrderedQueryable<T>);
}
return result;
}
/// <summary>
/// 判断里面是否已经调用过 OrderBy、OrderByDescending 这两个函数否,
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <returns></returns>
public static bool ContainsOrderBy<T>(this IQueryable<T> source)
{
bool result = false;
var expression = source.Expression;
if (expression.NodeType == ExpressionType.Call)
{
result = FindIOrderedQueryable(expression as MethodCallExpression);
}
return result;
}
/// <summary>
/// 递归子项找到 OrderBy、OrderByDescending 这两个函数的调用,
/// 其中一个子项有,就返回 True,都没有的话,就返回 False
/// </summary>
/// <param name="Expression"></param>
/// <returns></returns>
private static bool FindIOrderedQueryable(MethodCallExpression Expression)
{
bool result = false;
if (Expression.Method.Name == "OrderBy" || Expression.Method.Name == "OrderByDescending")
{
result = true;
}
else
{
foreach (var item in Expression.Arguments)
{
if (item.NodeType == ExpressionType.Call)
{
result = FindIOrderedQueryable(item as MethodCallExpression);
if (result) break;
}
}
}
return result;
}
}
核心代码其实是 FindIOrderedQueryable 这个函数,靠这货找出表达式中是否有调用过 OrderBy 或者 OrderByDescending 函数。
然后扩展函数根据这个结果来判断,现在给 IQueryable 加上的函数是 OrderBy 还是 ThenBy,
以后再也不用为往 IQueryable 后边加上 OrderBy 还是 ThenBy 操心了,一直加 OrderIf 扩展函数就可以,扩展函数自动判断是加入哪个函数。
以下是调用的示例:
class Program
{
static void Main(string[] args)
{
List<MyModel> list = new List<MyModel>();
for (int i = 0; i < 20; i++)
{
list.Add(new MyModel()
{
CreatedAt = DateTime.Now,
ID = i + 1,
OrderNumber = i,
Name = Char.ConvertFromUtf32(i)
});
}
var query = list.AsQueryable();
query = query.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name))
.Where(s => !string.IsNullOrEmpty(s.Name));
query = query
.OrderIf(s => s.OrderNumber, OrderByStatus.DESC, true)
.OrderIf(s => s.CreatedAt, OrderByStatus.ASC, true);
query = query.Where(s => s.CreatedAt.HasValue);
Console.WriteLine(query.ContainsOrderBy());
Console.ReadLine();
}
}
public class MyModel
{
[Key]
public long ID { get; set; }
public string Name { get; set; }
public DateTime? CreatedAt { get; set; }
public int? OrderNumber { get; set; }
}