【问题标题】:Dynamic Order By On Date With Entity Framework and Linq使用实体框架和 Linq 按日期动态排序
【发布时间】:2017-03-24 13:17:07
【问题描述】:

我在这里回答了另一个类似的问题,关于 NULL 值在 order by 中的最后一个。

Keep NULL rows last on Dynamic Linq Order By

我还想看看是否可以对具有以下条件的日期列执行相同的操作。

  1. 所有结束日期都在当前日期和顶部的所有项目,按最近即将发生的事件排序
  2. 使用结束日期跟踪所有过去的事件,并与当前日期进行比较,其中最近的结束日期已经过去了。我现在在纯 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”语法,代码可以识别fieldXDateTime类型,但是如何判断是否需要特殊排序呢?
  • 我会在 OrderBy 类中添加一个特殊字段。我唯一的问题是如何在动态 linq 语法中做到这一点。如您所见,我可以在 SQL 甚至强类型的 Linq 中做到这一点,只是没有这么复杂的东西。

标签: c# sql-server entity-framework linq sql-order-by


【解决方案1】:

据我了解,您有一个 DateTime 属性(可以称之为 Date),而不是常规排序

.OrderBy(x => x.Date)

有类似的东西

var baseDate = DateTime.Today;

您希望先按升序对未来的值进行排序,然后按降序对过去的值进行排序。

可以通过以下通用方式实现(在 LINQ to Objects 和 EF 中工作):

.OrderBy(x => x.Date >= baseDate ? x.Date : DateTime.MaxValue)
.ThenByDescending(x => x.Date >= baseDate ? DateTime.MinValue : x.Date)

要动态实现它,您可以在实现方法主体循环中插入以下内容:

if (order.Type == typeof(DateTime)) // && some other special condition
{
    var condition = Expression.GreaterThanOrEqual(
        order, Expression.Constant(DateTime.Today));
    var order1 = Expression.Condition(condition,
        order, Expression.Constant(DateTime.MaxValue));
    var order2 = Expression.Condition(condition,
        Expression.Constant(DateTime.MinValue), order);
    expression = CallOrderBy(expression,
        Expression.Lambda(order1, parameter), SortDirection.Ascending, initial);
    expression = CallOrderBy(expression,
        Expression.Lambda(order2, parameter), SortDirection.Descending, false);
    initial = false;
    continue;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多