LINQ सिंगल बनाम फर्स्ट


215

LINQ:

क्या यह अधिक कुशल है कि जब भी मुझे पता चले कि क्वेरी एक ही रिकॉर्डSingle() लौटाएगी , तो ऑपरेटर का उपयोग करना अधिक कुशल First()होगा ?

क्या कोई अंतर है?

जवाबों:


312

यदि आप एकल रिकॉर्ड की अपेक्षा कर रहे हैं, तो अपने कोड में स्पष्ट होना हमेशा अच्छा होता है।

मैं जानता हूँ कि दूसरों लिखा है तुम क्यों एक या अन्य उपयोग करें, लेकिन मैंने सोचा कि मैं उदाहरण देकर स्पष्ट करना चाहते हैं आप इसे क्यों, जब आप का उपयोग नहीं करना चाहिए मतलब अन्य।

नोट: मेरे कोड में, मैं आमतौर पर उपयोग करूंगा FirstOrDefault()और SingleOrDefault()यह एक अलग सवाल है।

उदाहरण के लिए, एक मेज जो Customersविभिन्न भाषाओं में एक समग्र कुंजी ( ID, Lang) का उपयोग करके संग्रहीत करता है :

DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).First();

ऊपर दिया गया यह कोड एक संभावित लॉजिक एरर (ट्रेस करना मुश्किल) पेश करता है। यह एक से अधिक रिकॉर्ड लौटाएगा (यह मानते हुए कि आपके पास कई भाषाओं में ग्राहक का रिकॉर्ड है) लेकिन यह हमेशा केवल पहला ही लौटाएगा ... जो कभी-कभी काम कर सकता है ... लेकिन अन्य नहीं। यह अप्रत्याशित है।

चूंकि आपका इरादा किसी एकल Customerउपयोग को वापस करने का है Single();

निम्नलिखित एक अपवाद फेंक देगा (जो इस मामले में आप चाहते हैं):

DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).Single();

फिर, आप बस अपने आप को माथे पर मारते हैं और अपने आप से कहते हैं ... ओओपीएस! मैं भाषा क्षेत्र भूल गया! निम्नलिखित सही संस्करण है:

DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 && c.Lang == "en" ).Single();

First() निम्नलिखित परिदृश्य में उपयोगी है:

DBContext db = new DBContext();
NewsItem newsitem = db.NewsItems.OrderByDescending( n => n.AddedDate ).First();

यह वन ऑब्जेक्ट लौटाएगा, और जब से आप छँटाई का उपयोग कर रहे हैं, यह सबसे हालिया रिकॉर्ड होगा जो वापस आ गया है।

Single()जब आपको लगता है कि इसका उपयोग करना चाहिए स्पष्ट रूप से हमेशा 1 रिकॉर्ड वापस करना चाहिए तो आपको तर्क त्रुटियों से बचने में मदद मिलेगी।


76
सिंगल और फर्स्ट दोनों तरीके फ़िल्टरिंग के लिए एक अभिव्यक्ति पैरामीटर ले सकते हैं, इसलिए जहां फ़ंक्शन आवश्यक नहीं है। उदाहरण: ग्राहक ग्राहक = db.Customers.Single (c => c.ID == 5);
जोश नं

6
@ जोशनेओ - मैं उत्सुक हूँ, क्या इसमें कोई अंतर है customers.Where(predicate).Single() customers.Single(predicate)?
drzaus

9
@drzaus - तार्किक रूप से, नहीं, वे दोनों विधेय के आधार पर लौटाए जाने वाले मूल्यों को फ़िल्टर करते हैं। हालाँकि, मैंने डिससैम्ड की जाँच की, और कहाँ (प्रेडिकेट करें) .Single () में साधारण केस में तीन अतिरिक्त निर्देश दिए हैं। इसलिए, जब मैं कोई आईएल विशेषज्ञ नहीं हूं, लेकिन यह प्रतीत होता है कि ग्राहक। सिंगल (विधेय) अधिक कुशल होना चाहिए।
जोश नू

5
@JoshNoe यह बिल्कुल विपरीत है क्योंकि यह निकलता है।
AgentFire


72

यदि यह मापदंड से मेल खाते एक से अधिक रिकॉर्ड पाता है, तो एकल अपवाद फेंक देगा। पहले हमेशा सूची से पहला रिकॉर्ड चुनेंगे। यदि क्वेरी सिर्फ 1 रिकॉर्ड लौटाती है, तो आप साथ जा सकते हैं First()

InvalidOperationExceptionयदि संग्रह खाली है तो दोनों अपवाद छोड़ देंगे । वैकल्पिक रूप से आप उपयोग कर सकते हैं SingleOrDefault()। यदि सूची खाली है, तो यह अपवाद नहीं फेंकेगा


29

एक()

क्वेरी का एकल विशिष्ट तत्व देता है

जब उपयोग करें : यदि ठीक 1 तत्व अपेक्षित है; नहीं 0 या 1 से अधिक। यदि सूची खाली है या एक से अधिक तत्व हैं, तो यह एक अपवाद फेंक देगा "अनुक्रम में एक से अधिक तत्व हैं"

SingleOrDefault ()

यदि कोई परिणाम नहीं मिला, तो क्वेरी का एक विशिष्ट तत्व या डिफ़ॉल्ट मान लौटाता है

जब उपयोग करें : जब 0 या 1 तत्व अपेक्षित हों। यदि सूची में 2 या अधिक आइटम हैं, तो यह एक अपवाद को फेंक देगा।

प्रथम()

कई परिणामों के साथ क्वेरी का पहला तत्व देता है।

जब उपयोग करें : जब 1 या अधिक तत्वों की उम्मीद की जाती है और आप केवल पहले चाहते हैं। यदि सूची में कोई तत्व नहीं है तो यह एक अपवाद को फेंक देगा।

FirstOrDefault ()

सूची का पहला तत्व किसी भी राशि के तत्वों के साथ लौटाता है, या सूची खाली होने पर एक डिफ़ॉल्ट मान।

जब उपयोग करें : जब कई तत्वों की उम्मीद की जाती है और आप केवल पहले चाहते हैं। या सूची खाली है और आप निर्दिष्ट प्रकार के लिए एक डिफ़ॉल्ट मान चाहते हैं, जैसा कि default(MyObjectType)। उदाहरण के लिए: यदि सूची प्रकार list<int>यह सूची से पहला नंबर लौटाएगा या यदि सूची खाली है तो 0। यदि यह है list<string>, तो यह सूची से पहला स्ट्रिंग लौटाएगा या सूची रिक्त होने पर रिक्त होगा।


1
अच्छी व्याख्या। मैं केवल वह परिवर्तन करूंगा जिसका उपयोग आप Firstतब कर सकते हैं जब 1 या अधिक तत्वों की अपेक्षा की जाती है , न केवल "1 से अधिक", और FirstOrDefaultकिसी भी राशि के तत्वों के साथ।
एंड्रयू

18

इन दोनों विधियों के बीच एक सूक्ष्म, शब्दार्थ भेद है।

Singleएक अनुक्रम से पहले (और केवल) तत्व को पुनः प्राप्त करने के लिए उपयोग करें जिसमें एक तत्व होना चाहिए और अधिक नहीं। यदि अनुक्रम में तत्व से अधिक है, तो आपके आह्वान का Singleअपवाद एक अपवाद होगा क्योंकि आपने संकेत दिया था कि केवल एक तत्व होना चाहिए।

Firstपहले तत्व को एक अनुक्रम से प्राप्त करने के लिए उपयोग करें जिसमें किसी भी संख्या में तत्व हो सकते हैं। यदि अनुक्रम में तत्व से अधिक है, तो आपके आह्वान का Firstअपवाद अपवाद नहीं होगा क्योंकि आपने संकेत दिया था कि आपको केवल अनुक्रम में पहले तत्व की आवश्यकता है और अधिक मौजूद होने पर परवाह न करें।

यदि अनुक्रम में कोई तत्व नहीं है, तो दोनों विधि कॉल अपवादों को फेंक देंगे क्योंकि दोनों विधियाँ कम से कम एक तत्व मौजूद होने की उम्मीद करती हैं।


17

यदि आप विशेष रूप से इस घटना में एक अपवाद नहीं चाहते हैं कि एक से अधिक वस्तु, उपयोग होFirst()

दोनों कुशल हैं, पहले आइटम ले लो। First()यह थोड़ा और अधिक कुशल है क्योंकि यह देखने के लिए कि कोई दूसरा आइटम है या नहीं, यह देखने के लिए परेशान नहीं करता है।

एकमात्र अंतर यह है कि Single()उम्मीद है कि शुरू करने के लिए गणना में केवल एक आइटम होगा, और एक से अधिक होने पर अपवाद फेंक देगा। यदि आप विशेष रूप से इस मामले में एक अपवाद चाहते हैं, .Single() तो आप उपयोग करते हैं


14

अगर मुझे याद है, तो सिंगल () चेक करता है कि पहले एक के बाद कोई दूसरा तत्व है (और यदि ऐसा है तो अपवाद छोड़ देता है), जबकि First () मिलने के बाद रुक जाता है। अनुक्रम खाली होने पर दोनों एक अपवाद को फेंक देते हैं।

व्यक्तिगत रूप से, मैं हमेशा फर्स्ट () का उपयोग करता हूं।


2
यदि वे गलत नहीं हैं तो SQL में वे First () TOP 1 और Single () TOP 2 का उत्पादन करते हैं।
मैथिज्स वेसल्स

10

Peformance के बारे में: एक सहकर्मी और मैं सिंगल बनाम फ़र्स्ट (या SingleOrDefault vs FirstOrDefault) के प्रदर्शन पर चर्चा कर रहे थे, और मैं इस बात के लिए बहस कर रहा था कि फ़र्स्ट (या फ़र्स्टऑर्डफ़ॉल्ट) और तेज़ हो जाएगा और प्रदर्शन में सुधार होगा (मैं अपना ऐप बनाने के बारे में हूँ) और तेज़ दौड़ें)।

मैंने स्टैक ओवरफ्लो पर कई पोस्ट पढ़ी हैं जो इस पर बहस करते हैं। कुछ का कहना है कि सिंगल के बजाय फर्स्ट का उपयोग करके छोटे प्रदर्शन लाभ हैं। ऐसा इसलिए है क्योंकि पहले केवल पहली वस्तु को लौटाएगा, जबकि एकल को यह सुनिश्चित करने के लिए सभी परिणामों को स्कैन करना होगा कि कोई डुप्लिकेट नहीं है (यानी: यदि यह तालिका की पहली पंक्ति में आइटम मिला, तो यह अभी भी हर दूसरी पंक्ति को स्कैन करेगा सुनिश्चित करें कि उस स्थिति से मेल खाने वाला दूसरा मूल्य नहीं है जो फिर एक त्रुटि फेंक देगा)। मैंने महसूस किया कि मैं "सिंगल" की तुलना में "फर्स्ट" तेज होने के साथ ठोस आधार पर था, इसलिए मैंने इसे साबित करने के लिए सेट किया और बहस को आराम देने के लिए रखा।

मैंने अपने डेटाबेस में एक परीक्षण सेट किया और ID UniqueIdentifier विदेशी UniqueIdentifier Info nvarchar (50) की 100 पंक्तियों को जोड़ दिया (संख्याओं की संख्या "0" से "999,9999"

मैंने डेटा लोड किया और आईडी को प्राथमिक कुंजी फ़ील्ड के रूप में सेट किया।

LinqPad का उपयोग करना, मेरा लक्ष्य यह दिखाना था कि यदि आपने सिंगल का उपयोग करते हुए 'फॉरेन' या 'इंफो' पर कोई मूल्य खोजा, तो यह फर्स्ट का उपयोग करने की तुलना में बहुत बुरा होगा।

मुझे मिले परिणामों की व्याख्या नहीं कर सकता। लगभग हर मामले में सिंगल या सिंगलऑर्फ़ॉल्ट का उपयोग करना थोड़ा तेज़ था। यह मेरे लिए कोई तार्किक अर्थ नहीं रखता है, लेकिन मैं इसे साझा करना चाहता था।

Ex: मैंने निम्नलिखित प्रश्नों का उपयोग किया:

var q = TestTables.First(x=>x.Info == "314638") ;
//Vs.
Var q = TestTables.Single(x=>x.Info =="314638") ; //(this was slightly faster to my surprise)

मैंने 'विदेशी' कुंजी क्षेत्र पर समान प्रश्नों की कोशिश की, जो यह सोचकर अनुक्रमित नहीं था कि पहले साबित होगा, लेकिन सिंगल हमेशा मेरे परीक्षणों में थोड़ा तेज था।


2
यदि यह डेटाबेस से अनुक्रमित फ़ील्ड पर है तो यह सुनिश्चित करने के लिए स्कैन करने की आवश्यकता नहीं है कि यह अद्वितीय है। यह पहले से ही जानता है कि यह है। इसलिए वहां कोई ओवरहेड नहीं है, और सर्वर साइड पर एकमात्र ओवरहेड सुनिश्चित कर रहा है कि केवल एक रिकॉर्ड वापस आए। प्रदर्शन का परीक्षण अपने आप में यह एक या दूसरे तरीके से निर्णायक नहीं है
23

1
मुझे नहीं लगता कि ये परिणाम किसी जटिल वस्तु पर समान होंगे यदि आप IComparer द्वारा उपयोग नहीं किए गए क्षेत्र पर खोज कर रहे थे।
एंथनी निकोल्स

यह एक और प्रश्न होना चाहिए। अपने परीक्षण के स्रोत को शामिल करना सुनिश्चित करें ।
सिनत्र

5

वे भिन्न हैं। दोनों यह कहते हैं कि परिणाम सेट खाली नहीं है, लेकिन एकल यह भी दावा करता है कि 1 से अधिक परिणाम नहीं है। मैं व्यक्तिगत रूप से उन मामलों में सिंगल का उपयोग करता हूं जहां मुझे केवल 1 परिणाम होने की उम्मीद है क्योंकि 1 से अधिक परिणाम प्राप्त करना एक त्रुटि है और शायद इस तरह का व्यवहार किया जाना चाहिए।


5

आप अंतर प्राप्त करने के लिए सरल उदाहरण की कोशिश कर सकते हैं। अपवाद को पंक्ति 3 पर फेंक दिया जाएगा;

        List<int> records = new List<int>{1,1,3,4,5,6};
        var record = records.First(x => x == 1);
        record = records.Single(x => x == 1);

3

बहुत से लोग जानते हैं कि मैं FirstOrDefault () का उपयोग करता हूं, लेकिन मैं SingleOrDefault () का उपयोग अधिक करता हूं क्योंकि अक्सर यह एक तरह से एक से अधिक डेटा असंगतता होगी। यह LINQ-to-Objects के साथ काम कर रहा है, हालांकि।


-1

कर्मचारी इकाई में रिकॉर्ड:

Employeeid = 1: इस आईडी के साथ केवल एक कर्मचारी

Firstname = Robert: इस नाम के एक से अधिक कर्मचारी

Employeeid = 10: इस आईडी वाला कोई कर्मचारी नहीं

अब यह समझना आवश्यक है कि विस्तार से क्या Single()और क्या First()मतलब है।

एक()

सिंगल () एक एकल रिकॉर्ड को वापस करने के लिए उपयोग किया जाता है, जो विशिष्ट रूप से एक तालिका में मौजूद है, इसलिए नीचे दी गई क्वेरी कर्मचारी को वापस कर देगी, employeed =1क्योंकि हमारे पास केवल एक कर्मचारी है जिसका Employeed1. है। यदि हमारे पास दो रिकॉर्ड हैं, EmployeeId = 1तो यह एक त्रुटि फेंकता है (देखें) दूसरी क्वेरी में नीचे त्रुटि जहां हम एक उदाहरण के लिए उपयोग कर रहे हैं Firstname

Employee.Single(e => e.Employeeid == 1)

उपरोक्त एक एकल रिकॉर्ड लौटाएगा, जिसमें 1 है employeeId

Employee.Single(e => e.Firstname == "Robert")

उपरोक्त एक अपवाद को फेंक देगा क्योंकि मल्टीपल रिकॉर्ड के लिए तालिका में हैं FirstName='Robert'। अपवाद होगा

InvalidOperationException: अनुक्रम में एक से अधिक तत्व होते हैं

Employee.Single(e => e.Employeeid == 10)

यह, फिर से, एक अपवाद को फेंक देगा क्योंकि आईडी = 10 के लिए कोई रिकॉर्ड मौजूद नहीं है। अपवाद होगा

InvalidOperationException: अनुक्रम में कोई तत्व नहीं हैं।

क्योंकि EmployeeId = 10यह अशक्त हो जाएगा, लेकिन जैसा कि हम उपयोग कर रहे हैं Single()वह एक त्रुटि फेंक देगा। अशक्त त्रुटि को संभालने के लिए हमें उपयोग करना चाहिए SingleOrDefault()

प्रथम()

पहले () कई अभिलेखों से रिटर्न इसी क्रम में क्रमबद्ध क्रमबद्ध क्रमबद्ध होते हैं, birthdateइसलिए यह 'रॉबर्ट' जो सबसे पुराना है, लौटाएगा।

Employee.OrderBy(e => e. Birthdate)
.First(e => e.Firstname == "Robert")

ऊपर को DOB के अनुसार सबसे पुराना, रॉबर्ट लौटना चाहिए।

Employee.OrderBy(e => e. Birthdate)
.First(e => e.Employeeid == 10)

ऊपर एक अपवाद फेंक देंगे क्योंकि आईडी = 10 के लिए कोई रिकॉर्ड मौजूद नहीं है। एक अशक्त अपवाद से बचने के लिए हमें इसके FirstOrDefault()बजाय उपयोग करना चाहिए First()

नोट: हम केवल First()/ Single()जब हम पूरी तरह से सुनिश्चित कर सकते हैं कि यह एक शून्य मान नहीं लौटा सकता है।

दोनों कार्यों में SingleOrDefault () या FirstOrDefault () का उपयोग किया जाता है, जो एक शून्य अपवाद को संभाल लेगा, कोई रिकॉर्ड नहीं होने की स्थिति में यह अशक्त हो जाएगा।


कृपया अपना उत्तर बताएं।
मृमाविन

1
@MrMaavin मैंने अपडेट किया है, कृपया मुझे बताएं कि क्या यह अब आपके लिए समझ में आता है?
शेरिफ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.