LINQ에서 여러 "주문"


1582

두 개의 테이블이 movies있으며 먼저 categoryIDcategories 로 정렬 한 다음 Name 별로 정렬 된 목록을 얻습니다 .

영화 테이블에는 ID와 Name 이라는 세 개의 열이 있습니다. 카테고리 테이블에는 ID 및 Name의 두 열이 있습니다.

나는 다음과 같은 것을 시도했지만 작동하지 않았다.

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

괄호 안의 람다 식은 항목을 주문하는 데 사용할 수있는 값을 반환해야합니다. m.CategoryID는 항목을 주문하는 데 사용할 수있는 숫자입니다. 그러나 "m.CategoryID, m.Name"은이 문맥에서 의미가 없습니다.
chiccodoro

9
. 그럼 당신이 찾고있는 것입니까?
eka808

만일 우연히 당신이 그것들을 내림차순으로 정렬하고 싶다면 여기 로 가십시오.
RBT

답변:


2831

이것은 당신을 위해 작동해야합니다 :

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

4
물론 답을 주셔서 감사합니다 ... 그러나 "orderBy"를 두 번 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
두 번째 "있는 OrderBy는"해당 항목 최초의 "있는 OrderBy"과 재주문 결과 컬렉션을 통해 작동하기 때문에 @devendra는, 결과는 다릅니다

68
나는 지구상에서 어떻게 알지 못하고이 세상을 떠났 ThenBy습니까?! ( 편집 : .NET 4.0에서 소개 된 것처럼 보이며 눈에 띄지 않게 미끄러졌습니다.)
Jordan Gray

13
이것은 LINQ가 추가 된 이후에있었습니다. 이 답변은 .NET 4.0 이전 버전입니다.
Nathan W

10
그렇다. 나는 문서 페이지 의 3.5 버전 드롭 다운에 있지 않다고 성급하게 결론 지었다 . 버전 정보를 철저히 조사해야했습니다. 수정 해 주셔서 감사합니다. :)
Jordan Gray

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

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

9
@ Lodewijk : 나는 당신이 정확히 거꾸로 있다고 생각합니다. 예를 들어 row.Name은 기본 열이고 row.Category secondary는에 해당 _db.Movies.Orderby(c => c.Category).OrderBy(n => n.Name)합니다. 제공하는 두 스 니펫은 OP가 아닌 서로 동일합니다.
Scott Stafford

6
Linq에 SQL 구문을 사용할 때의 유일한 단점은 모든 기능이 지원되는 것은 아니며 전부는 아니라는 것입니다.
Joshua G

74

새로운 걸 더하다":

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

그것은 내 상자에서 작동합니다. 정렬하는 데 사용할 수있는 것을 반환합니다. 두 개의 값을 가진 객체를 반환합니다.

다음과 같이 유사하지만 결합 된 열을 기준으로 정렬하는 것과 다릅니다.

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.NameCategoryID가 인 경우 잘못된 주문이 생성됩니다 int. 예를 들어, id = 123, name = 5times 인 항목은 id = 1234 뒤에, name = something 뒤에 나타납니다. int 비교가 발생할 수있는 문자열 비교는 비효율적입니다.
AaronLS

7
익명 형식으로 주문하려고하면 "적어도 하나의 개체가 IComparable을 구현해야합니다."라는 메시지와 함께 ArgumentException이 발생합니다. 나는 이것을 할 때 다른 사람들이 비교자를 선언해야한다는 것을 알았습니다. stackoverflow.com/questions/10356864/…를 참조하십시오 .
Robert Gowland

4
이것은 절대적으로 잘못입니다. 익명 유형의 속성에 대한 순서가 없기 때문에 ICompariable 구현이없는 새로운 익명 유형에 의한 순서는 작동 할 수 없습니다. CategoryID를 먼저 정렬할지 또는 Name을 먼저 정렬할지 여부는 알지 못합니다 (반대 순서로 정렬해야하는 경우는 제외).
Triynko

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을 생성하십시오 (이름 및 CategoryId가 전환됨).

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

1
@Marie 사용 사례를 명확하게 이해하지 못했습니다. 예를 들어 속성 ​​목록에서 순서를 어떻게 동적으로 작성합니까? 이것이 유일한 방법입니다. 공감하거나 재고하지 마십시오. 감사합니다.
sjkm

그럴 수 있지. 여전히 혜택을 볼 수 없지만 투표권을 다시 가져갑니다
Marie

이 작업을 수행 할 nullable datetime
것인가

16

가장 쉬운 방법은 아니지만 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());

항목 중 하나에 대해 순서를 내림차순으로 전환 해야하는 경우 그에 따라 Compare() 방법 내에서 x와 y를 전환하십시오 MovieComparer.


1
나는 다른 알고리즘을 사용할 준비가 된 다른 비교 객체를 포함하여 비교로 이상한 일을 할 수 있기 때문에 이보다 더 일반적이라고 생각합니다. 이것은 IComparable 인터페이스를 구현하는 클래스를 작성하는 방법을 배우기 전에 내가 선호하는 솔루션보다 낫습니다.
Gerard ONeill

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... 대신에 하나의 표현식으로 논리를 작성하려는 경우 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.