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




linq-to-sql (9)

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


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

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


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


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

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

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


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

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


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

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

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

يجب أيضًا تنفيذ الترتيب حسب تاريخ الإنشاء باستخدام عملية Where (من غير المحتمل أن يكون لديك كيان واحد فقط ، والفرز لن يكون ذا فائدة كبيرة) ؛ ومع ذلك فهذا يعني أنك تريد فرز كل الكيانات - إذا كنت تريد واحدًا فقط ، استخدم 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();

لا أفهم سبب استخدامك 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 ، لأنه يحتاج إلى معرفة وجود أكثر من سجل واحد.


من أجل LINQ -> SQL:

SingleOrDefault

  • سيقوم بإنشاء استعلام مثل "حدد * من المستخدمين حيث userid = 1"
  • حدد السجل المطابق ، واستبعاد الاستثناء في حالة العثور على أكثر من سجل واحد
  • استخدمه إذا كنت تجلب البيانات استنادًا إلى عمود المفتاح الأساسي / الفريد

FirstOrDefault

  • سيؤدي إلى إنشاء طلب بحث مثل "حدد أعلى 1 * من المستخدمين حيث userid = 1"
  • حدد الصفوف المطابقة الأولى
  • استخدم إذا كنت تجلب البيانات استنادًا إلى عمود المفتاح غير الأساسي / الفريد




linq-to-sql