.net - LINQ:وقت استخدام SingleOrDefault مقابل FirstOrDefault()مع معايير التصفية




linq-to-sql (12)

النظر في أساليب ملحق IEnumerable SingleOrDefault() و FirstOrDefault()

مستندات MSDN التي SingleOrDefault :

إرجاع العنصر الوحيد في تسلسل ، أو قيمة افتراضية إذا كان التسلسل فارغًا ؛ يلقي هذا الأسلوب استثناء إذا كان هناك أكثر من عنصر واحد في التسلسل.

بينما FirstOrDefault من MSDN (يفترض عند استخدام OrderBy() أو OrderByDescending() أو لا شيء على الإطلاق) ،

إرجاع العنصر الأول من التسلسل

ضع في اعتبارك مجموعة من الاستعلامات على سبيل المثال ، وليس من الواضح دائمًا متى تستخدم هاتين الطريقتين:

var someCust = db.Customers
.SingleOrDefault(c=>c.ID == 5); //unlikely(?) to be more than one, but technically COULD BE

var bobbyCust = db.Customers
.FirstOrDefault(c=>c.FirstName == "Bobby"); //clearly could be one or many, so use First?

var latestCust = db.Customers
.OrderByDescending(x=> x.CreatedOn)
.FirstOrDefault();//Single or First, or does it matter?

سؤال

ما هي الاصطلاحات التي تتبعها أو تقترحها عند اتخاذ قرار باستخدام SingleOrDefault() و FirstOrDefault() في استعلامات LINQ الخاصة بك؟


Answers

لا أفهم سبب استخدامك FirstOrDefault(x=> x.ID == key) عندما يمكن أن يؤدي ذلك إلى استرداد النتائج بسرعة أكبر إذا كنت تستخدم Find(key) . إذا كنت تستعلم باستخدام المفتاح الأساسي للجدول ، فإن القاعدة الأساسية هي استخدام Find(key) دائمًا. يجب استخدام FirstOrDefault للأشياء الأصلية مثل (x=> x.Username == username) إلخ.

هذا لا يستحق التراجع لأن عنوان السؤال لم يكن محددًا على linq على DB أو Linq إلى List / IEnumerable إلخ.


لم يذكر أحد أن FirstOrDefault المترجمة في SQL يقوم بأعلى سجل 1 ، و SingleOrDefault لا TOP 2 ، لأنه يحتاج إلى معرفة وجود أكثر من سجل واحد.


إذا كانت مجموعة النتائج الخاصة بك تقوم بإرجاع 0 سجل:

  • إرجاع SingleOrDefault القيمة الافتراضية للنوع (على سبيل المثال الافتراضي لـ int 0)
  • إرجاع FirstOrDefault القيمة الافتراضية للنوع

إذا قمت بتعيين النتيجة بإرجاع سجل واحد:

  • SingleOrDefault بإرجاع هذا السجل
  • FirstOrDefault بإرجاع هذا السجل

إذا كانت مجموعة النتائج الخاصة بك تقوم بإرجاع العديد من السجلات:

  • SingleOrDefault يطرح استثناء
  • إرجاع FirstOrDefault السجل الأول

استنتاج:

إذا كنت تريد طرح استثناء إذا كانت مجموعة النتائج تحتوي على العديد من السجلات ، استخدم SingleOrDefault .

إذا كنت تريد دومًا 1 سجل بغض النظر عن ما FirstOrDefault مجموعة النتائج ، استخدم FirstOrDefault


SingleOrDefault: أنت تقول أن "على الأكثر" هناك عنصر واحد يطابق الاستعلام أو الافتراضي FirstOrDefault: أنت تقول أن هناك عنصر واحد "على الأقل" يطابق الاستعلام أو الافتراضي

قل ذلك بصوت مرتفع في المرة القادمة التي تحتاج إلى الاختيار ، ومن المرجح أن تختار بحكمة. :)


أستخدم SingleOrDefault في المواقف حيث يفرض SingleOrDefault أن تكون النتيجة إما صفرية أو واحدة. إذا كان هناك المزيد ، فهذه حالة خطأ ، وهو أمر مفيد.


في المثال الأخير الخاص بك:

var latestCust = db.Customers
.OrderByDescending(x=> x.CreatedOn)
.FirstOrDefault();//Single or First, or doesn't matter?

نعم إنها كذلك. إذا حاولت استخدام SingleOrDefault() ونتائج الاستعلام في أكثر من سجل ستحصل والاستثناء. المرة الوحيدة التي يمكنك استخدامها بأمان SingleOrDefault() عندما تتوقع 1 و 1 فقط نتيجة ...


شيء واحد هو غاب في الردود ....

في حالة وجود عدة نتائج ، يمكن لـ FirstOrDefault بدون طلب بواسطة إرجاع نتائج مختلفة استنادًا إلى أي إستراتيجية الفهرس التي تم استخدامها من قبل الملقم.

شخصيا لا أستطيع أن أرى FirstOrDefault في رمز لأنه يقول لي المطور لم يهتم بالنتائج. مع أمر على الرغم من أنه يمكن أن يكون مفيدا كوسيلة لفرض أحدث / أقرب. لقد قمت بتصحيح الكثير من المشكلات التي تسببها المطورين المهملة باستخدام FirstOrDefault.


كلاهما عامل العناصر ويتم استخدامها لتحديد عنصر واحد من تسلسل. لكن هناك اختلاف بسيط بينهما. عامل SingleOrDefault () طرح استثناء إذا تمت استيفاء أكثر من عناصر الشرط حيث لا يتم طرح FirstOrDefault () أي استثناء لنفسه. هنا هو المثال.

List<int> items = new List<int>() {9,10,9};
//Returns the first element of a sequence after satisfied the condition more than one elements
int result1 = items.Where(item => item == 9).FirstOrDefault();
//Throw the exception after satisfied the condition more than one elements
int result3 = items.Where(item => item == 9).SingleOrDefault();

عندما تستخدم SingleOrDefault ، يجب بوضوح أن يؤدي الاستعلام إلى نتيجة واحدة على الأكثر. من ناحية أخرى ، عند استخدام FirstOrDefault ، يمكن أن يقوم الاستعلام بإرجاع أي قدر من النتائج ولكنك تذكر أنك تريد أول واحد فقط.

أنا شخصيا العثور على دلالات مختلفة جدا واستخدام واحدة مناسبة ، اعتمادا على النتائج المتوقعة ، ويحسن قابلية القراءة.


هناك

  • فرق معنوي
  • فرق في الأداء

بين الاثنين.

الفرق الدلالة:

  • FirstOrDefault إرجاع عنصر الأول من المحتمل متعددة (أو الافتراضي إذا لم يكن موجوداً).
  • يفترض SingleOrDefault وجود عنصر واحد SingleOrDefault (أو افتراضي إذا لم يكن موجودًا). عناصر متعددة هي انتهاك للعقد ، يتم طرح استثناء.

فرق الأداء

  • FirstOrDefault عادة ما يكون أسرع ، فإنه يتكرر حتى يعثر على العنصر ، ويتعين عليه فقط تكرار الأمر بالكامل عند عدم العثور عليه. في كثير من الحالات ، هناك احتمال كبير للعثور على عنصر.

  • يحتاج SingleOrDefault إلى التحقق مما إذا كان هناك عنصر واحد فقط ومن ثم يقوم دائمًا بتكرار الكل. على وجه الدقة ، فإنه يتكرر حتى يجد عنصرًا ثانيًا ويلقي استثناءً. لكن في معظم الحالات ، لا يوجد عنصر آخر.

استنتاج

  • استخدم FirstOrDefault إذا كنت لا تهتم بعدد العناصر الموجودة أو عندما لا يمكنك تحمل التحقق من التفرد (على سبيل المثال في مجموعة كبيرة جدًا). عندما تقوم بفحص التفرد في إضافة العناصر إلى المجموعة ، قد يكون التحقق من هذه العناصر مرة أخرى باهظًا جدًا عند البحث عن تلك العناصر.

  • استخدم SingleOrDefault إذا لم يكن عليك الاهتمام بالأداء أكثر من اللازم وتريد التأكد من أن افتراض بند واحد واضح للقارئ ويتم التحقق عند وقت التشغيل.

في الممارسة العملية ، يمكنك استخدام First / FirstOrDefault غالباً حتى في الحالات عندما تفترض عنصر واحد ، لتحسين الأداء. يجب عليك أن تتذكر أن Single / SingleOrDefault يمكن أن تحسن قابلية القراءة (لأنها تشير إلى افتراض عنصر واحد) والثبات (لأنها تقوم بفحصه) واستخدامه بشكل مناسب.


في حالاتك ، سأستخدم ما يلي:

اختر بالمعرف == 5: لا بأس في استخدام SingleOrDefault هنا ، لأنك تتوقع كيان واحد [أو لا شيء] ، إذا كان لديك أكثر من كيان واحد به ID 5 ، فهناك شيء خاطئ ويستحق بالتأكيد الاستثناء.

عند البحث عن أشخاص يماثل اسمهم الأول "Bobby" ، يمكن أن يكون هناك أكثر من واحد (من المحتمل جدا أن أفكر) ، لذلك لا ينبغي عليك استخدام Single أو First ، فقط حدد بـ Where-operation (إذا كان "Bobby" يقوم بالعودة أكثر من اللازم كيانات ، يجب على المستخدم تحسين بحثه أو اختيار إحدى النتائج التي تم إرجاعها)

يجب أيضًا تنفيذ الترتيب حسب تاريخ الإنشاء باستخدام عملية Where (من غير المحتمل أن يكون لديك كيان واحد فقط ، والفرز لن يكون ذا فائدة كبيرة) ؛ ومع ذلك فهذا يعني أنك تريد فرز كل الكيانات - إذا كنت تريد واحدًا فقط ، استخدم FirstOrDefault ، سوف يرمي واحد في كل مرة إذا حصلت على أكثر من كيان واحد.






.net linq linq-to-sql