LINQ ऑर्डरबाई बनाम तबबी


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

आपको कई कॉल के बजाय निश्चित रूप से उपयोग करना चाहिए ।ThenByOrderBy

मैं यह सुझाव दूंगा:

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माध्यमिक (टेरीटरी) ऑर्डर करने वाले अनुमानों को निर्दिष्ट करने के लिए (बार-बार) का उपयोग करें।

: प्रभावी ढंग से, इसे इस तरह लगता है कि OrderBy(...).ThenBy(...).ThenBy(...)तरह अनुक्रम आप किसी भी दो वस्तुओं के लिए एक एकल समग्र तुलना बनाने की अनुमति देता है, और फिर एक बार है कि समग्र तुलना का उपयोग कर। यह लगभग निश्चित रूप से आप क्या चाहते हैं।


2
Thats मैंने क्या सोचा लेकिन, किसी कारण के लिए ऑर्डरबी, तब, तबबे सही ढंग से छँटाई नहीं लगती है इसलिए मुझे आश्चर्य हुआ कि क्या मैं इसे सही तरीके से उपयोग कर रहा था।
DazManCat

14
ध्यान दें कि क्वेरी सिंटैक्स में ऑर्डर करने के लिए कीवर्ड वास्तव में ऑर्डरबाय है, ऑर्डर द्वारा नहीं। (
पांडेंट्री के

1
जॉन, कुछ मेरे लिए एक साथ फिट नहीं होता है, लेकिन आपको बिल्कुल खंड नहीं करना चाहिए (जो कि लिन्क धाराप्रवाह सिंटैक्स का उपयोग करके कई आदेशों को लागू करने से संबंधित है, क्योंकि यह स्थानीय प्रश्नों में तबबे से अनुवाद करता है ): यह अच्छा प्रदर्शन नहीं करता है (क्योंकि यह पूरे अनुक्रम को फिर से व्यवस्थित करता है ) - क्या आप 2 या 3 क्रम का मतलब पूरे अनुक्रम को फिर से जोड़ते हैं? यदि ऐसा है, तो यह फिर भी पूर्व-आदेश देने वाले अनुक्रम को फिर से जारी करने के आदेश के बाद तबबे पर कैसे अनुवाद करेगा?
विवेके

@Veverke: यह पूरे अनुक्रम को फिर से व्यवस्थित करता है, लेकिन एक स्थिर तरीके से, इसलिए यदि दो मानों का समान z मान है, तो आदेश y पर और फिर x पर निर्भर करेगा।
जॉन स्कीट

1
@Veverke: OrderBy(a).OrderBy(b).OrderBy(c)अभी भी पूर्ववर्ती प्रकार के आउटपुट का उपयोग करता है, और पूरी चीज़ को पुन : व्यवस्थित करता है, लेकिन यह मौजूदा क्रम (पूर्ववर्ती चरण से) को संरक्षित करता है, जहां दो तत्व नई तुलना में बराबर हैं। सोचिए हमारे पास बस है OrderBy(a).OrderBy(b)। परिणाम OrderBy(a)बढ़ते aक्रम में हैं, और फिर उन के अनुसार पुन: व्यवस्थित किया जाता है b। अंतिम परिणाम में, यदि दो मानों का bमूल्य समान है , तो वे aक्रमबद्ध होने के कारण क्रमबद्ध होंगे - इसलिए यह इसके बराबर है OrderBy(b).ThenBy(a)
जॉन स्कीट

2

मुझे सामान्य तरीके से प्रश्न बनाने की कोशिश में यह अंतर परेशान करने वाला लगा, इसलिए मैंने उचित क्रम में ऑर्डरबाय / थेबी का उत्पादन करने के लिए थोड़ा सहायक बनाया, जैसा कि आप चाहते हैं।

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

यदि आप एक से अधिक क्षेत्र छाँटना चाहते हैं तो इसके लिए जाएँ:

इस तरह

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

0

यदि आप एकाधिक कुंजियों के साथ खेल रहे हैं, तो हाँ, आपको कभी भी कई ऑर्डरबी का उपयोग नहीं करना चाहिए। तब ऑर्डर सुरक्षित है क्योंकि यह ऑर्डरबी के बाद प्रदर्शन करेगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.