题 LINQ中的多个“order by”


我有两张桌子, movies 和 categories,我得到一个有序列表 的categoryID 先是然后再来 名称

电影表有三列, ID,名称和CategoryID。 类别表2有列, ID和名称

我试过类似下面的东西,但它没有用。

var movies = _db.Movies.OrderBy( m => { m.CategoryID, m.Name })

1383
2017-11-18 13:34


起源


这就是为什么这不起作用:括号中的lambda表达式应该返回一个可用于对项目进行排序的值:m.CategoryID是一个可用于对项目进行排序的数字。但是“m.CategoryID,m.Name”在这种情况下没有意义。 - chiccodoro
包括System.Linq; :)
看一眼 LINQ中的SQL查询:order by。它解释了如何将常见的SQL查询转换为LINQ语法。其中一个例子包括多列的排序。 - Steven Wexler
那你正在寻找什么? - eka808
如果您有任何机会想要按降序对它们进行排序 这里 是要走的路。 - RBT


答案:


这应该适合你:

var movies = _db.Movies.OrderBy(c => c.Category).ThenBy(n => n.Name)

2527
2017-11-18 13:41



谢谢你的回答当然......但不是 Var movies = _db.Movies.Orderby(c => c.Category).ThenBy(n => n.Name)     如果我使用 Var movies = _db.Movies.Orderby(c => c.Category).OrderBy(n => n.Name)   2次“orderBy”为什么结果不同?
@devendra,结果是不同的,因为第二个“OrderBy”在第一个“OrderBy”的结果集合上工作并重新排序其项目
在我不知不觉的情况下,我到底怎么走了 ThenBy?! (编辑: 看起来它是在.NET 4.0中引入的,它解释了它是如何在我不知不觉中滑过我的。) - Jordan Gray
自从LINQ被添加以来,这一直存在。这个答案是.NET 4.0之前的。 - Nathan W
是的,我的结论是太仓促,基于3.5不在版本下拉列表中 文档页面;我应该一直向下看版本信息。谢谢你的纠正。 :) - Jordan Gray


使用非lambda查询语法LINQ,您可以这样做:

var movies = from row in _db.Movies 
             orderby row.Category, row.Name
             select row;

[编辑评论]要控制排序顺序,请使用关键字 ascending (这是默认值,因此不是特别有用)或 descending,像这样:

var movies = from row in _db.Movies 
             orderby row.Category descending, row.Name
             select row;

552
2017-09-30 14:49



在这种语法中,有没有办法在降序和非降序之间来回翻转? - ehdv
实际上,你的答案相当于 _db.Movies.Orderby(c => c.Category).OrderBy(n => n.Name)。更正确的是 from row in _db.Movies orderby row.Category descending orderby row.Name select row - Lodewijk
@Lodewijk:我相信你完全倒退了。您的示例将最终将row.Name作为主列,将row.Category作为辅助,这相当于 _db.Movies.Orderby(c => c.Category).OrderBy(n => n.Name)。您提供的两个片段彼此相同,而不是OP。 - Scott Stafford
使用Linq的SQL语法的唯一缺点是并非所有函数都受支持,大多数但不是全部 - b729sefc


添新”:

var movies = _db.Movies.OrderBy( m => new { m.CategoryID, m.Name })

这适用于我的盒子。它确实返回了可用于排序的东西。它返回一个具有两个值的对象。

类似但不同于按组合列排序,如下所示。

var movies = _db.Movies.OrderBy( m => (m.CategoryID.ToString() + m.Name))

67
2018-06-22 14:27



将其用于数字时要小心。 - WoF_Angel
您可以根据需要使用OrderByDescending和ThenBy,或OrderBy和ThenByDescending。 - Ali Shah Ahmed
我很确定 .OrderBy( m => new { m.CategoryID, m.Name }) 和 .OrderBy( m => new { m.Name, m.CategoryID }) 将产生相同的结果,而不是尊重预期的优先级。它有时似乎只是巧合地给你你想要的顺序。另外 m.CategoryID.ToString() + m.Name 如果CategoryID是一个,将产生不正确的排序 int。例如,id = 123,name = 5times的东西将出现在id = 1234之后,name = something而不是之前。在可能发生int比较的字符串比较中,效率也不高。 - AaronLS
当我尝试按匿名类型排序时,我得到一个带有消息“至少有一个对象必须实现IComparable”的ArgumentException。我看到其他人在这样做时必须声明一个比较器。看到 stackoverflow.com/questions/10356864/... 。 - Robert Gowland
这是绝对错误的。使用没有ICompariable实现的新匿名类型进行排序是行不通的,因为匿名类型的属性没有顺序。它不知道是先对CategoryID进行排序还是首先对Name进行排序,更不用说如果要按相反的顺序对它们进行排序。 - Triynko


使用DataContext上的以下行将DataContext上的SQL活动记录到控制台 - 然后您可以确切地看到您的linq语句从数据库请求的内容:

_db.Log = Console.Out

以下LINQ语句:

var movies = from row in _db.Movies 
             orderby row.CategoryID, row.Name
             select row;

var movies = _db.Movies.OrderBy(m => m.CategoryID).ThenBy(m => m.Name);

产生以下SQL:

SELECT [t0].ID, [t0].[Name], [t0].CategoryID
FROM [dbo].[Movies] as [t0]
ORDER BY [t0].CategoryID, [t0].[Name]

然而,在Linq中重复OrderBy似乎会反转生成的SQL输出:

var movies = from row in _db.Movies 
             orderby row.CategoryID
             orderby row.Name
             select row;

var movies = _db.Movies.OrderBy(m => m.CategoryID).OrderBy(m => m.Name);

产生以下SQL(Name和CategoryId被切换):

SELECT [t0].ID, [t0].[Name], [t0].CategoryID
FROM [dbo].[Movies] as [t0]
ORDER BY [t0].[Name], [t0].CategoryID

18
2018-02-18 21:03



谢谢@Oliver这是一个很好的详细解释,说明如何观察差异并为您的情况做出正确的调用 - Chris Schaller


使用LINQ至少还有一种方法可以做到这一点,尽管不是最简单的方法。 你可以使用 OrberBy() 使用的方法 IComparer。首先你需要 实施一个 IComparer 为了 Movie 像这样的类:

public class MovieComparer : IComparer<Movie>
{
    public int Compare(Movie x, Movie y)
    {
        if (x.CategoryId == y.CategoryId)
        {
            return x.Name.CompareTo(y.Name);
        }
        else
        {
            return x.CategoryId.CompareTo(y.CategoryId);
        }
    }
}

然后您可以使用以下语法订购电影:

var movies = _db.Movies.OrderBy(item => item, new MovieComparer());

如果您需要将其中一个项目的顺序切换为降序,只需将x和y切换到其中 Compare()  的方法 MovieComparer 因此。


12
2018-04-03 14:07



我喜欢这个比一般更通用,因为你可以做比较奇怪的事情,包括不同的比较对象和不同的算法准备好了。在学习thenby之前,这比我的首选解决方案更好,这是创建一个实现IComparable接口的类。 - Gerard ONeill
自2012年(.NET 4.5版)起,您不必创建类 MovieComparer 自己;相反,你可以做到 _db.Movies.OrderBy(item => item, Comparer<Movie>.Create((x, y) => { if (x.CategoryId == y.CategoryId) { return x.Name.CompareTo(y.Name); } else { return x.CategoryId.CompareTo(y.CategoryId); } }));。当然,如果您更喜欢将逻辑编写为一个表达式,而不是 if...else那么lamda (x, y) => expr可以更简单。 - Jeppe Stig Nielsen


我已经创建了一些扩展方法(如下所示),因此您不必担心是否已经订购了IQueryable。如果您想按多个属性订购,请按以下步骤操作:

// We do not have to care if the queryable is already sorted or not. 
// The order of the Smart* calls defines the order priority
queryable.SmartOrderBy(i => i.Property1).SmartOrderByDescending(i => i.Property2);

如果您动态创建排序,这尤其有用。从要排序的属性列表中。

public static class IQueryableExtension
{
    public static bool IsOrdered<T>(this IQueryable<T> queryable) {
        if(queryable == null) {
            throw new ArgumentNullException("queryable");
        }

        return queryable.Expression.Type == typeof(IOrderedQueryable<T>);
    }

    public static IQueryable<T> SmartOrderBy<T, TKey>(this IQueryable<T> queryable, Expression<Func<T, TKey>> keySelector) {
        if(queryable.IsOrdered()) {
            var orderedQuery = queryable as IOrderedQueryable<T>;
            return orderedQuery.ThenBy(keySelector);
        } else {
            return queryable.OrderBy(keySelector);
        }
    }

    public static IQueryable<T> SmartOrderByDescending<T, TKey>(this IQueryable<T> queryable, Expression<Func<T, TKey>> keySelector) {
        if(queryable.IsOrdered()) {
            var orderedQuery = queryable as IOrderedQueryable<T>;
            return orderedQuery.ThenByDescending(keySelector);
        } else {
            return queryable.OrderByDescending(keySelector);
        }
    }
}

12
2018-06-08 14:49



这个答案是黄金!我将查询queryable.IsOrdered()与此帖子的答案结合起来,以获得一个排序方向的方法: stackoverflow.com/questions/388708 - SwissCoder
这样Linq的实现应该放在第一位! OrderBy设计糟糕...... - Andrzej Martyna


如果使用通用存储库

> lstModule = _ModuleRepository.GetAll().OrderBy(x => new { x.Level,
> x.Rank}).ToList();

其他

> _db.Module.Where(x=> ......).OrderBy(x => new { x.Level, x.Rank}).ToList();

0
2017-07-17 14:29