【问题标题】:DISTINCT() and ORDERBY issueDISTINCT() 和 ORDERBY 问题
【发布时间】:2012-09-14 17:05:01
【问题描述】:

我正在学习 LINQ-to-SQL,一切都很顺利,直到发生了奇怪的事情:

我试图以distinct 为例,因此,我使用 Northwind dabatase 编写了以下查询:

var query = 
    from o in db.Orders
    orderby o.CustomerID
    select new
    {
        o.CustomerID
    };

如果我打印 LINQ-to-SQL 为存储在 query 中的查询生成的 SQL,它看起来像这样:

SELECT [t0].[CustomerID]
FROM [dbo].[Orders] AS [t0]
ORDER BY [t0].[CustomerID]

因此,像往常一样,查询会在Orders 表中按字母顺序为每个Order 带来所有CustomerID

但是!如果我像这样使用Distinct() 方法:

var query = (
    from o in db.Orders
    orderby o.CustomerID
    select new
    {
        o.CustomerID
    }).Distinct();

查询带来Distinct子句的预期结果,但CustomerIDs没有排序尽管我写了orderby o.CustomerID

第二个 LINQ 查询的 SQL 查询如下:

SELECT DISTINCT [t0].[CustomerID]
FROM [dbo].[Orders] AS [t0]

正如我们所见,**ORDER BY 子句不见了。这是为什么呢?

为什么当我使用Distinct() 方法时ORDER BY 子句消失了?

【问题讨论】:

  • 顺便说一句,对于这样的查询来说,lambda 语法要简单得多:var query = db.Orders.Select(o=>o.CustomerId).Distinct();

标签: c# .net linq linq-to-sql


【解决方案1】:

来自Queryable.Distinct documentation

预期的行为是它返回源中唯一项的无序序列。

换句话说,当您在现有的 IQueryable 上使用 Distinct() 时,任何订单都会丢失。

你想要的可能更像是这样,一个 OrderBy() Distinct() 完成之后;

var query = (from o in db.Orders
             select new
             {
                 o.CustomerID
             }).Distinct().OrderBy(x => x.CustomerID);

【讨论】:

    【解决方案2】:

    尝试重新排列成员以将 OrderBy 放在 Distinct 之后。你必须恢复到方法链:

    db.Orders.Select(o=>o.CustomerId).Distinct().OrderBy(id=>id);
    

    无论如何,这将是在 Enumerable Linq 中设置查询的更有效方法,因为 OrderBy 将只对唯一项目而不是对所有项目进行操作。另外,根据MSDN,Enumerable.Distinct 无论如何也不保证元素的返回顺序,所以在去重之前排序是没有意义的。

    【讨论】:

    • ...是的,它是:msdn.microsoft.com/en-us/library/…。问题是,为什么 Distinct 不保持输入元素的顺序,而仅仅通过 yield-return 就可以很容易地做到这一点?
    • @KeithS 你读过你的链接了吗...“结果序列是无序的。”当它被内置到设计中时,它不是一个错误。
    • @JTorres 我完全根据链接中的声明编辑了答案。在我之前的评论中,我同意 asawyer 的观点,即这确实是设计使然。问题仍然存在;当它可以很容易地以稳定的方式实现时,他们为什么要这样设计它?
    • @KeithS 这可能会提供一些见解msmvps.com/blogs/jon_skeet/archive/2010/12/30/…
    • @asawyer - 显然 Jon Skeet 同意我的观点; “自然”实现,因此天真的期望,是 Distinct 将按照与输入相同的顺序流式传输元素,删除后续重复项(返回第一个重复项,其他重复项被抑制);但他也指出,实际上内置实现并非如此。
    【解决方案3】:

    由于使用distinct,返回列表的顺序不保证。 LinqToSql 足够聪明,可以识别这一点,因此它会忽略它。

    如果您在 Distinct 之后下订单,一切都会如您所愿。

    var query = (from o in db.Orders
                 select new
                 {
                     o.CustomerID
                 }).Distinct().OrderBy(o => o.CustomerID);
    

    var query = db.Orders.Select(o => o.CustomerID).Distinct().OrderBy(o => o.CustomerID);
    

    请参阅这篇文章以获得澄清:

    http://programminglinq.com/blogs/marcorusso/archive/2008/07/20/use-of-distinct-and-orderby-in-linq.aspx

    【讨论】:

      【解决方案4】:

      你可以用这个结构模拟 ORDERBY 和 DISTINCT:

      var distinctItems = employees.GroupBy(x => x.EmpID).OrderBy(x => x).Select(y => y.First());
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-19
        • 1970-01-01
        • 1970-01-01
        • 2021-01-30
        • 2014-09-05
        • 1970-01-01
        相关资源
        最近更新 更多