我有另一个类似的问题在这里得到了回答,关于 NULL 值是订单的最后一个。
在 Dynamic Linq Order By 上将 NULL 行保留在最后 https://stackoverflow.com/questions/42277259/keep-null-rows-last-on-dynamic-linq-order-by
我还想看看是否可以使用具有以下条件的日期列执行相同的操作。
- 所有结束日期均位于当前日期且位于顶部的所有项目,按最近即将发生的事件排序
-
接下来是使用结束日期的所有过去事件,并与当前日期与过去的最近结束日期进行比较。我现在在纯 SQL 中做了类似的事情。
(CASE
WHEN ev.EndDate >= GETDATE() THEN 1
ELSE 2
END) ASC,
(CASE
WHEN ev.EndDate >= GETDATE() THEN ev.EndDate
ELSE ev.StartDate
END) ASC,
示例:当前日期 2017 年 3 月 24 日
EndDate
2017年3月25日
2017 年 4 月 15 日
2017年7月29日
2017年3月23日
2016年2月22日
当前代码
public static class OrderByHelper
{
public static IOrderedQueryable<T> ThenBy<T>(this IEnumerable<T> source, string orderBy)
{
return source.AsQueryable().ThenBy(orderBy);
}
public static IOrderedQueryable<T> ThenBy<T>(this IQueryable<T> source, string orderBy)
{
return OrderBy(source, orderBy, false);
}
public static IOrderedQueryable<T> OrderBy<T>(this IEnumerable<T> source, string orderBy)
{
return source.AsQueryable().OrderBy(orderBy);
}
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string orderBy)
{
return OrderBy(source, orderBy, true);
}
private static IOrderedQueryable<T> OrderBy<T>(IQueryable<T> source, string orderBy, bool initial)
{
if (string.IsNullOrWhiteSpace(orderBy))
orderBy = "ID DESC";
var parameter = Expression.Parameter(typeof(T), "x");
var expression = source.Expression;
foreach (var item in ParseOrderBy(orderBy, initial))
{
var order = item.PropertyName.Split('.')
.Aggregate((Expression)parameter, Expression.PropertyOrField);
if (!order.Type.IsValueType || Nullable.GetUnderlyingType(order.Type) != null)
{
var preOrder = Expression.Condition(
Expression.Equal(order, Expression.Constant(null, order.Type)),
Expression.Constant(1), Expression.Constant(0));
expression = CallOrderBy(expression, Expression.Lambda(preOrder, parameter), item.Direction, initial);
initial = false;
}
expression = CallOrderBy(expression, Expression.Lambda(order, parameter), item.Direction, initial);
initial = false;
}
return (IOrderedQueryable<T>)source.Provider.CreateQuery(expression);
}
private static Expression CallOrderBy(Expression source, LambdaExpression selector, SortDirection direction, bool initial)
{
return Expression.Call(
typeof(Queryable), GetMethodName(direction, initial),
new Type[] { selector.Parameters[0].Type, selector.Body.Type },
source, Expression.Quote(selector));
}
private static string GetMethodName(SortDirection direction, bool initial)
{
return direction == SortDirection.Ascending ?
(initial ? "OrderBy" : "ThenBy") :
(initial ? "OrderByDescending" : "ThenByDescending");
}
private static IEnumerable<OrderByInfo> ParseOrderBy(string orderBy, bool initial)
{
if (String.IsNullOrEmpty(orderBy))
yield break;
string[] items = orderBy.Split(',');
foreach (string item in items)
{
string[] pair = item.Trim().Split(' ');
if (pair.Length > 2)
throw new ArgumentException(String.Format("Invalid OrderBy string '{0}'. Order By Format: Property, Property2 ASC, Property2 DESC", item));
string prop = pair[0].Trim();
if (String.IsNullOrEmpty(prop))
throw new ArgumentException("Invalid Property. Order By Format: Property, Property2 ASC, Property2 DESC");
SortDirection dir = SortDirection.Ascending;
if (pair.Length == 2)
dir = ("desc".Equals(pair[1].Trim(), StringComparison.OrdinalIgnoreCase) ? SortDirection.Descending : SortDirection.Ascending);
yield return new OrderByInfo() { PropertyName = prop, Direction = dir, Initial = initial };
initial = false;
}
}
private class OrderByInfo
{
public string PropertyName { get; set; }
public SortDirection Direction { get; set; }
public bool Initial { get; set; }
}
private enum SortDirection
{
Ascending = 0,
Descending = 1
}
}