LINQの複数の「注文者」


1582

との2つのテーブルがmoviesありcategories、最初にcategoryID、次にNameで順序付けされたリストを取得します

ムービーテーブルには、ID、Name、CategoryIDの 3つの列があります。カテゴリテーブルには、IDとNameの 2つの列があります

次のようなものを試しましたが、うまくいきませんでした。

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

これが機能しない理由は次のとおりです。かっこ内のラムダ式は、アイテムの注文に使用できる値を返すことになっています。m.CategoryIDは、アイテムの注文に使用できる数値です。しかし、「m.CategoryID、m.Name」はこのコンテキストでは意味がありません。
チッコドロ

9
.ThenByは何を検索していますか?
eka808 14

万が一、降順で並べ替えたい場合は、ここに進んでください。
RBT 2017

回答:


2831

これはあなたのために働くはずです:

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

4
もちろん答えてくれてありがとう...しかし、 「orderBy」を2回Var movies = _db.Movies.Orderby(c => c.Category).ThenBy(n => n.Name) 使用する代わりに 、 Var movies = _db.Movies.Orderby(c => c.Category).OrderBy(n => n.Name)なぜ結果が異なるのですか?

147
@ devendra、2番目の「OrderBy」が最初の「OrderBy」の結果であるコレクションに対して機能し、そのアイテムを並べ替えるため、結果は異なります

68
ThenBy一体どうして私は知らないうちにずっとこの世に行ってきたのですか?(編集:それが.NET 4.0で導入されたように見えます。それはそれが気付かれずに私をすり抜けてしまった方法を説明しています。)
ジョーダングレイ

13
これは、LINQが追加されて以来存在しています。この回答は.NET 4.0より前です。
Nathan W

10
はい、私はあまりにも速すぎて、ドキュメントページのバージョンドロップダウンに3.5がないことに基づいて結論しまし。バージョン情報をずっと見下ろしていたはずです。訂正ありがとうございます。:)
ジョーダン・グレイ

594

非ラムダ、クエリ構文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;

1
この構文では、降順と非順を切り替える方法はありませんか?
ehdv、2011年

1
実際、あなたの答えはと同等_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 '31

9
@Lodewijk:私はあなたがそれを正確に逆に持っていると信じています。あなたの例では、row.Nameがプライマリ列であり、row.Categoryがセカンダリであり、これはと同等です_db.Movies.Orderby(c => c.Category).OrderBy(n => n.Name)。指定する2つのスニペットは、OPではなく互いに同等です。
スコットスタッフォード

6
LinqにSQL構文を使用することの唯一の欠点は、すべてではないがほとんどの関数がサポートされていることです
Joshua G

74

新しく追加する":

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

それは私の箱で動作します。ソートに使用できるものを返します。2つの値を持つオブジェクトを返します。

次のように、結合された列による並べ替えと似ていますが異なります。

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

21
数値に使用する場合は注意してください。
WoF_Angel

7
必要に応じて、OrderByDescendingとThenBy、またはOrderByとThenByDescendingを使用できます。
Ali Shah Ahmed

6
意図した優先順位を尊重するのではなく、同じ結果が得られる.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 2013年

7
匿名型で注文しようとすると、「少なくとも1つのオブジェクトはIComparableを実装する必要があります。」というメッセージを含むArgumentExceptionが発生します。これを行う場合、他の人が比較演算子を宣言する必要があるのがわかります。stackoverflow.com/questions/10356864/…を参照してください。
Robert Gowland 14

4
これは間違いです。匿名型のプロパティには順序がないため、ICompariable実装を持たない新しい匿名型による順序付けは機能しません。最初にCategoryIDでソートするのか、最初にNameでソートするのかはわかりません。逆に、それらをソートする場合はなおさらです。
Triynko 2015

29

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を生成します(名前とカテゴリIDが切り替えられます)。

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

24

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

1
この答えは金です​​!私は、この記事から答えをqueryable.IsOrdered()のチェックを組み合わせますソート方向をとり、単一の方法で持っている:stackoverflow.com/questions/388708
SwissCoder

1
このようにして、Linqの実装は最初に行う必要があります。OrderByのデザインは適切ではありません...
Andrzej Martyna 2018年

1
@Marieあなたは明らかにユースケースを理解していません。たとえば、プロパティのリストから動的に順序を作成するにはどうすればよいですか?これが唯一の方法です。反対投票や再考は行わないでください。ありがとうございました。
sjkm 2018

けっこうだ。まだメリットはわかりませんが、投票を
Marie

意志を持つこの作品nullable datetime
アギー

16

最も簡単ではありませんが、LINQを使用してこれを行う方法が少なくとも1つあります。を使用する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());

アイテムの1つについて降順に順序を切り替える必要がある場合Compare() は、MovieComparerそれに応じてのメソッド内でxとyを切り替えます。


1
さまざまなアルゴリズムを備えたさまざまな比較オブジェクトを準備するなど、比較で奇妙なことができるので、私はこれよりも一般的であることが好きです。これは、thebybyについて学習する前に、IComparableインターフェイスを実装するクラスを作成するという私の推奨ソリューションよりも優れています。
Gerard ONeill、2015

1
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... ではなく1つの式として記述したい場合elseは、ラムダ(x, y) => exprをより単純にすることができます。
Jeppe Stig Nielsen

3

汎用リポジトリを使用する場合

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

そうしないと

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

1
匿名の式は、エンティティフレームワークコアによってローカルで解析されます。LINQ式を翻訳できなかったため、ローカルで評価されます。
alhpe
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.