Entity Framework 4 Single () проти First () проти FirstOrDefault ()


119

У мене диявол часу знаходить порівняння різних способів запиту по одному предмету, і коли кожен використовувати.

У когось є посилання, яке порівнює все це, або швидке пояснення того, чому ви б використовували одне над іншим? Чи є ще більше операторів, про які я не знаю?

Дякую.

Відповіді:


205

Ось огляд різних методів:

  • Find () - коли ви хочете отримати товар за первинним ключем. Це повернеться до нуля, якщо він не зможе знайти елемент. Він перегляне контекст перед тим, як перейти до бази даних (на що вказував Ярон у коментарях), що може бути важливим фактором ефективності, якщо вам потрібно отримати одне і те ж об'єкт кілька разів, поки живий той самий контекст.

  • Single () - коли ви очікуєте, що запит буде повернуто точно одним елементом. Це призведе до виключення, якщо запит не повертає рівно один елемент.

  • SingleOrDefault () - коли ви очікуєте, що за запитом буде повернуто нуль або один елемент (тобто ви не впевнені, чи існує елемент із заданим ключем). Це призведе до виключення, якщо запит не поверне нуль або один елемент.

  • Перший () - коли ви очікуєте, що один або кілька елементів будуть повернуті запитом, але ви хочете отримати доступ лише до першого елемента у вашому коді (замовлення може бути важливим у запиті тут). Це призведе до виключення, якщо запит не повертає хоча б один елемент.

  • FirstOrDefault () - коли ви очікуєте, що за запитом буде повернуто нуль або більше елементів, але ви хочете отримати доступ лише до першого елемента у вашому коді (тобто ви не впевнені, чи існує елемент із заданим ключем)


1
Це залежить від сценарію. Якщо ви знаєте, що ви завжди повинні отримувати один запис назад від db, не більше, не менше, для даного запиту, тоді Single () є "правильним" для використання. В інших ситуаціях інші можуть бути більш доречними. У попередніх версіях EF ми обмежувалися First () та FirstOrDefault (), які працюють у сценаріях, де ви очікуєте єдиного запису, але вони не попереджають вас, якщо ви отримаєте більше, ніж один єдиний запис, який може бути важливим залежно від ситуація.
Стів Віллок

1
Дякую. Я більше не можу бачити себе потрібним First (), де Single () не був би кращим. Якби я був менш щільним, я впевнений, що міг би оцінити / зрозуміти, коли все-таки використовувати First ().
asfsadf

1
Перший () має найбільше значення в тому випадку, коли ви хочете отримати лише той об'єкт, який має найвищий або найнижчий рівень того, що ви замовляєте. Наприклад, знайдіть мені продаж з найвищим загальним значенням. Sales.OrderByDescending(s => s.TotalValue).First();
Майк Чемберлен

5
Усі коментарі виглядають важливою різницею. Find () - єдиний метод, який шукає контекст, перш ніж натиснути на db.
Ярон Леві

5
Інший момент - це запит на базу даних sql, Singleабо SingleOrDefaultбуде запит на 2 записи (обмеження 2), в той час як Firstабо FirstOrDefaultбуде запит на 1 (обмеження 1).
Барт Калікто

22

Я завжди схильний використовувати FirstOrDefault. Якщо ви дійсно хочете бути вимогливими до продуктивності, тоді вам варто скористатися FirstOrDefaultв EF. Під обкладинками SingleOrDefaultвикористовується запит top (2), оскільки він повинен перевірити, чи є другий рядок, який відповідає критеріям, і якщо він є, він викидає виняток. В основному SingleOrDefaultви говорите, що ви хочете викинути виняток, якщо ваш запит повертає більше 1 запису.


5
Ви коли-небудь вимірювали різницю між показниками продуктивності FirstOrDefaultта SingleOrDefaultбути значущим? Я б сказав, що це передчасна оптимізація в більшості випадків.
Стівен

Я схильний використовувати Single()або SingleOrDefault()коли повертаю те, що повинно існувати лише одне . Причиною цього я є виявлення помилок, роблячи погано написані запити, які повертають більше, ніж повинні, не вдається. Принаймні, на мій погляд, це допоможе підтримувати дані в системі. Звичайно, це повільніше, але я б здогадався, що це не набагато повільніше, і я готовий заплатити цю ціну.
mortb

15

Це дійсно дуже просто: Singleповертає один елемент і кидає виняток, якщо його немає або більше одного. Firstповерне перший елемент або кине, коли його немає. FirstOrDefaultповерне перший елемент або поверне значення за замовчуванням (що є nullу випадку, якщо даний тип є еталонним типом), коли його немає.

Це поведінка, якою повинен володіти API. Однак зауважте, що основна реалізація може мати іншу поведінку. Хоча Entity Framework підкоряється цьому, O / RM на зразок LLBLGen також може повертатися nullпри дзвінках, Firstщо є дуже дивною річчю. Це було дуже дивне (і вперте) рішення дизайнера IMO.


Дякую Стівену Я думаю, мені все ще цікаво, чому ти використовуєш один над іншим? Я завжди використовував FirstOrDefault (), і мені було цікаво, чому багато нових прикладів, які я бачив, перейшли на Single (). Чи є причина перейти на Single ()? Чи є інші, які також роблять те саме, що я повинен вважати замість цього?
asfsadf

7
Якщо вам подобається, що ваш код "швидко провалюється", First () та Single () нехай ваш код точніше скаже те, що очікується (щоб воно могло вийти з ладу)
Frank Schwieterman

3
Я повністю згоден з Франком. Йдеться також про спілкування про наміри. Singleчітко виражає, що ви очікуєте, що результат матиме лише один елемент.
Стівен

8

Чотири методи мають своє місце; Хоча у вас дійсно є лише дві різні операції.

  • Перший - Очікуючи набір результатів, який містить кілька елементів, дайте мені перший елемент у цьому наборі.
  • Одномісний - очікуючи повернення одного результату, поверніть мені цей предмет.

Версія xxxxOrDefault () просто додає "Я не хочу вважати порожній результат набору винятковою обставиною".


Гаразд, тому мені здається, що First () рідко стане у нагоді. Мені важко придумати сценарій, коли Single () не був би першим варіантом. Ви маєте швидку відмову від руки, випадково? Дякую.
asfsadf

3
На жаль, багато розробників використовують First () або FirstOrDefault () виключно як захисний захід, думаючи, що це уникне виключення, коли воно справді просто має потенціал приховати реальні проблеми.
Метт Х

3

З іншого боку, ви можете розділити ці методи за основною логікою, наприклад:

  • Метод буде безпосередньо запитувати базу даних : Single (), SingleOrDefault (), First (), FirstOrDefault ()
  • Метод буде виконувати пошук у кеші, перш ніж навіть видавати запит до бази даних : Find ()

Деякі відомості про ефективність, особливо у другому випадку, можна переглянути тут: https://msdn.microsoft.com/en-us/data/hh949853.aspx?f=255&MSPPError=-2147217396#3

Крім того, в першій групі ви можете визначити складні запити, але за допомогою методу Find () ви можете надати лише ключ сутності для пошуку.


0

Single () і SingleOrDefault () зазвичай використовується для унікальних ідентифікаторів, таких як ідентифікатори, тоді як First () або FirstOrDefault () зазвичай використовуються для запиту, який може мати декілька результатів, але вам потрібно лише "Top 1" .

Single () або First () буде кидати виняток, якщо результат не повертається, SingleOrDefault () та FirstOrDefault () ловить виняток і повертає null або default (ResultDataType).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.