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




7 Answers

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

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

النظر في أساليب ملحق 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 الخاصة بك؟




هناك

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

بين الاثنين.

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

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

فرق الأداء

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

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

استنتاج

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

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

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




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




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

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

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

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




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

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

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




كما أفهم الآن ، سوف يكون SingleOrDefault جيدًا إذا كنت SingleOrDefault عن بيانات مضمونة لتكون فريدة من نوعها ، أي فرض قيود DB مثل المفتاح الأساسي.

أو هل هناك طريقة أفضل للاستعلام عن المفتاح الأساسي.

بافتراض أن TableAcc لدي

AccountNumber - Primary Key, integer
AccountName
AccountOpenedDate
AccountIsActive
etc.

وأريد الاستعلام عن AccountNumber 987654 ، وأنا استخدم

var data = datacontext.TableAcc.FirstOrDefault(obj => obj.AccountNumber == 987654);



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

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




Related

.net linq linq-to-sql