【发布时间】:2017-03-24 13:17:07
【问题描述】:
我在这里回答了另一个类似的问题,关于 NULL 值在 order by 中的最后一个。
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 日
结束日期
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
}
}
【问题讨论】:
-
两个查询,也许?
-
也许吧,但是你如何用字符串做一个动态案例。阅读上一个问题的链接。
-
你可以把那个sql查询转换成linq查询,那有什么问题呢?
-
我认为这是可行的,但仅适用于单个日期字段。您将如何在
orderBy字符串中指定该行为?目前支持“field1 ASC, field2 DESC”语法,代码可以识别fieldX为DateTime类型,但是如何判断是否需要特殊排序呢? -
我会在 OrderBy 类中添加一个特殊字段。我唯一的问题是如何在动态 linq 语法中做到这一点。如您所见,我可以在 SQL 甚至强类型的 Linq 中做到这一点,只是没有这么复杂的东西。
标签: c# sql-server entity-framework linq sql-order-by