使用实体框架和Linq按日期动态订购 [英] Dynamic Order By On Date With Entity Framework and Linq

查看:74
本文介绍了使用实体框架和Linq按日期动态订购的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我还有另一个类似的问题,关于NULL值在哪个顺序上排在最后.

I had another question similar answered here on NULL values being last on an order by.

将NULL行保留在动态Linq排序依据上

我还想看看是否可以使用符合以下条件的Date列来做同样的事情.

I would also like to see if I can do the same thing with a Date column with the following criteria.

  1. 所有结束日期在当前日期且在顶部的项目,按最近发生的事件排序
  2. 后跟所有使用结束日期的过去事件,并将当前日期与经过和向下传递的最近结束日期进行比较.我现在在纯SQL中做类似的事情.

  1. All items with all end dates on the current date and up at the top, sorted by the most recent upcoming event
  2. Followed by all past events using the end date and comparing to the current date with the most recent end date passed and down. I do something similar in pure SQL at the moment.

        (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日

Example: Current Date 3/24/2017

EndDate

2017/3/25

3/25/2017

4/15/2017

4/15/2017

2017年7月29日

7/29/2017

2017/3/23

3/23/2017

2/22/2016

2/22/2016

当前代码

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
    }
}

推荐答案

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

The way I understand, you have a DateTime property (ley call it Date), and instead of regular sort

.OrderBy(x => x.Date)

具有类似

var baseDate = DateTime.Today;

您要先按升序对将来的值进行排序,然后再按降序对过去的值进行排序.

you want to sort the future values first in ascending order followed by the past values in descending order.

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

It can be achieved in the following generic way (works in LINQ to Objects as well as EF):

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

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

To implement that dynamically, you could insert the following inside the implementation method body loop:

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;
}

这篇关于使用实体框架和Linq按日期动态订购的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆