LINQ按另一个属性排序是第一个属性等于给定值

时间:2019-03-02 10:16:46

标签: c# linq

我正在尝试按用户手动设置的发布日期订购列表。如果未设置发布日期,我想按创建日期(由系统自动设置)排序。

这是我到目前为止尝试过的方法,但是即使发布的日期值不等于其默认值,似乎该集合也仅按创建日期排序:

viewModel.News = model.Content.Children<NewsItem>().OrderBy(x => x.PublishDate == default(DateTime) ? x.CreateDate : x.PublishDate).ToList();

仅供参考。PublishDate和CreatedDate属性是只读的。

2 个答案:

答案 0 :(得分:1)

如果发布日期相同,是否可以按创建日期排序?如果是,那么可以将这种方法与ThenBy一起使用:

viewModel.News = model.Content.Children<NewsItem>().OrderBy(x => x.PublishDate).ThenBy(x => x.CreateDate).ToList(); 

答案 1 :(得分:0)

您忘了告诉我们您的model.Content.Children<NewsItem>()序列是IEnumerable还是IQueryable

如果您不知道这意味着什么:是您的进程,那么它将进行枚举,还是另一个进程,例如数据库管理系统为您获取数据?

如果序列为IEnumerable,我的建议是创建一个Compare类为您进行比较。这样做的好处是,如果将来您决定以其他方式订购,您的LINQ不会改变。缺点:这不适用于数据库(这就是为什么我问它是否可查询的原因)。 IEnumerable情况在结尾。

IQueryable

IQueryable最常用于要由另一个进程(例如数据库管理系统)执行查询的情况。因为它将由其他人执行,所以功能仅限于相当简单的功能。毕竟:您可能已经创建了VeryUsefulFunction(),但是SQL不知道这一点。

  

如果未设置发布日期,我想按创建日期排序

因此,我们需要选择要提取OrderDate的位置:PublishedDate或CreatedDate。之后,您可以按OrderDate订购

var result = model.Content.Children<NewsItem>().Select(newsItem => new
{
    OrderDate = newsItem.PublishedDate ?? newsItem.CreatedDate,
    Item = newsItem,
})
.OrderBy(newsItem => newsItem.OrderDate)

// if desired, throw away the OrderDate:
.Select(newsItem => newsItem.Item)

几个LINQ到实体将不接受空合并运算符(??)。在这种情况下,您将在运行时遇到异常。如果是这种情况,则需要使用三元运算符(?:)

IEnumerable

您也可以将IQueryable代码用作Enumerable。但是,在这种情况下,您将“早期新闻项”的概念与处理过程混合在一起,使它们的可读性,可测试性和可变性降低。例如,如果您需要一遍又一遍地订购新闻项目的概念,则必须复制粘贴此代码。此外,如果将来您想以不同的顺序(例如,按新闻项目的长度排序),则需要查找并重写所有对新闻项目进行排序的LINQ语句。

更好的办法是定义哪个新闻在另一个新闻之前。为此,您编写了一个实现IComparer<NewsItem>的类。

class NewsItemComparer : IComparer<NewsItem>
{
    public static readonly IComparer<NewsItem> Default = new NewsItemComparer();
    private static readonly IComparer<DateTime> dateComparer = Comparer<DateTime>.Default;

    public int Compare(NewsItem x, NewItem y)
    {
        // TODO: decide what to do if x or y NULL: exception? first? last?

        return dateComparer.Compare(x.PublishedDate ?? x.CreatedDate,
                                    y.PublishedDate ?? y.CreatedDate);
    }
}

用法:

var result = model.Content.Children<NewsItem>()
    .OrderBy(newsItem => newsItem, NewsItemComparer.Default);

这看起来比将比较代码放入查询中更加整洁。如果您决定以不同的方式进行比较,则此代码以及所有其他要比较NewsItems的代码都不会更改。实施各种比较方法甚至相当简单,例如按日期,按长度或按作者,...