LINQ OrderBy 대 ThenBy


123

누구든지 차이점이 무엇인지 설명 할 수 있습니까?

tmp = invoices.InvoiceCollection
              .OrderBy(sort1 => sort1.InvoiceOwner.LastName)
              .OrderBy(sort2 => sort2.InvoiceOwner.FirstName)
              .OrderBy(sort3 => sort3.InvoiceID);

tmp = invoices.InvoiceCollection
              .OrderBy(sort1 => sort1.InvoiceOwner.LastName)
              .ThenBy(sort2 => sort2.InvoiceOwner.FirstName)
              .ThenBy(sort3 => sort3.InvoiceID);

데이터 3 개 단위로 주문하려는 경우 올바른 방법은 무엇입니까?

답변:


212

당신은해야 확실히 사용하는 ThenBy여러보다는 OrderBy통화.

나는 이것을 제안 할 것이다 :

tmp = invoices.InvoiceCollection
              .OrderBy(o => o.InvoiceOwner.LastName)
              .ThenBy(o => o.InvoiceOwner.FirstName)
              .ThenBy(o => o.InvoiceID);

매번 같은 이름을 사용할 수있는 방법에 유의하십시오. 이것은 또한 다음과 동일합니다.

tmp = from o in invoices.InvoiceCollection
      orderby o.InvoiceOwner.LastName,
              o.InvoiceOwner.FirstName,
              o.InvoiceID
      select o;

전화하면 OrderBy여러 번 하면 시퀀스가 완전히 세 번 재정렬 되므로 최종 호출이 효과적으로 지배적입니다. 당신은 할 수 있습니다 (LINQ의 개체) 쓰기

foo.OrderBy(x).OrderBy(y).OrderBy(z)

이는

foo.OrderBy(z).ThenBy(y).ThenBy(x)

정렬 순서는 안정적이지만 절대로 다음을 수행해서는 안됩니다.

  • 읽기 어렵다
  • 잘 수행되지 않습니다 (전체 시퀀스를 재정렬하기 때문에)
  • 잘 될지도 몰라 다른 공급자 (예 : LINQ to SQL) 에서는 제대로 작동 하지 않을
  • 기본적으로 방법이 아닙니다 OrderBy 사용하도록 설계된 이 .

요점 OrderBy "가장 중요한"주문 계획을 제공하는 것입니다. 그런 다음 ThenBy(반복적으로) 사용 하여 2 차, 3 차 등 주문 예측을 지정합니다.

효과적으로 다음과 같이 생각해보십시오. OrderBy(...).ThenBy(...).ThenBy(...)두 개체에 대해 단일 복합 비교를 작성한 다음 해당 복합 비교를 사용하여 시퀀스를 한 번 정렬 할 수 있습니다. 그것은 거의 확실히 당신이 원하는 것입니다.


2
그게 내가 생각한 것이지만 어떤 이유로 OrderBy, ThenBy, ThenBy가 올바르게 정렬되지 않는 것 같아서 올바르게 사용하고 있는지 궁금했습니다.
DazManCat

14
쿼리 구문에서 ordering 키워드는 실제로 order by가 아니라 orderby입니다. ( pedantry에 대해 죄송합니다-한 번 Jon Skeet 게시물을 수정했다고 말하고 싶었습니다 )
fostandy

1
Jon, 무언가가 저에게 맞지 않지만 섹션 은 절대로해서는 안됩니다 (이는 로컬 쿼리에서 ThenBy로 번역되기 때문에 linq 유창한 구문을 사용하여 다중 주문을 적용하는 것과 관련이 있음). 잘 수행되지 않습니다 (왜냐하면 전체 시퀀스를 재정렬) - 전체 시퀀스를 재정렬하여 두 번째 또는 세 번째 순서를 의미합니까? 그렇다면 이전 순서를 버리고 시퀀스를 다시 정렬 한 후에도 ThenBy로 어떻게 번역됩니까?
Veverke

@Veverke : 전체 시퀀스를 재정렬하지만 안정된 방식으로 두 값이 동일한 z 값을 갖는 경우 순서는 y와 x에 따라 달라집니다.
Jon Skeet

1
@Veverke : OrderBy(a).OrderBy(b).OrderBy(c)여전히 이전 정렬의 출력을 사용하고 전체를 다시 정렬하지만 새 비교에서 두 요소가 동일한 기존 순서 (이전 단계의)를 유지합니다. 우리가 OrderBy(a).OrderBy(b). 결과는 OrderBy(a)증가에 a주문하고라면에 따른 재 배열된다 b. 최종 결과에서 두 값이 동일한 ba을 갖는 경우 정렬이 안정적이기 때문에 정렬되므로 OrderBy(b).ThenBy(a).
Jon Skeet

2

일반적인 방식으로 쿼리를 작성하려고 할 때 이러한 구분이 성가시다는 것을 알았으므로 원하는만큼 많은 종류의 OrderBy / ThenBy를 적절한 순서로 생성하도록 약간의 도우미를 만들었습니다.

public class EFSortHelper
{
  public static EFSortHelper<TModel> Create<TModel>(IQueryable<T> query)
  {
    return new EFSortHelper<TModel>(query);
  }
}  

public class EFSortHelper<TModel> : EFSortHelper
{
  protected IQueryable<TModel> unsorted;
  protected IOrderedQueryable<TModel> sorted;

  public EFSortHelper(IQueryable<TModel> unsorted)
  {
    this.unsorted = unsorted;
  }

  public void SortBy<TCol>(Expression<Func<TModel, TCol>> sort, bool isDesc = false)
  {
    if (sorted == null)
    {
      sorted = isDesc ? unsorted.OrderByDescending(sort) : unsorted.OrderBy(sort);
      unsorted = null;
    }
    else
    {
      sorted = isDesc ? sorted.ThenByDescending(sort) : sorted.ThenBy(sort)
    }
  }

  public IOrderedQueryable<TModel> Sorted
  {
    get
    {
      return sorted;
    }
  }
}

사용 사례에 따라 여러 가지 방법으로 사용할 수 있지만, 예를 들어 정렬 열 및 방향 목록을 문자열 및 부울로 전달한 경우 반복하여 다음과 같은 스위치에서 사용할 수 있습니다.

var query = db.People.AsNoTracking();
var sortHelper = EFSortHelper.Create(query);
foreach(var sort in sorts)
{
  switch(sort.ColumnName)
  {
    case "Id":
      sortHelper.SortBy(p => p.Id, sort.IsDesc);
      break;
    case "Name":
      sortHelper.SortBy(p => p.Name, sort.IsDesc);
      break;
      // etc
  }
}

var sortedQuery = sortHelper.Sorted;

의 결과는 sortedQuery여기에있는 다른 답변이주의를 기울이기 때문에 계속해서 의지하는 대신 원하는 순서로 정렬됩니다.


1
또는 일부 확장 메서드 stackoverflow.com/a/45486019/1300910
huysentruitw

1

둘 이상의 필드를 정렬하려면 ThenBy로 이동하십시오.

이렇게

list.OrderBy(personLast => person.LastName)
            .ThenBy(personFirst => person.FirstName)

0

예, 여러 키를 사용하는 경우 OrderBy를 여러 개 사용해서는 안됩니다. ThenBy는 OrderBy 이후에 수행되므로 더 안전합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.