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

#c# #asp.net-mvc #linq #lambda

#.net #linq #entity-framework #entity-framework-4 #linq-to-entities

Вопрос:

Я с трудом нахожу сравнение различных способов запроса одного элемента и когда использовать каждый из них.

У кого-нибудь есть ссылка, которая сравнивает все это, или краткое объяснение того, почему вы бы использовали одно поверх другого? Есть ли еще операторы, о которых я не знаю?

Спасибо.

Ответ №1:

Вот обзор различных методов:

  • Find() — когда вы хотите получить элемент по первичному ключу. Это вернет значение null, если не удастся найти элемент. Он будет выглядеть в контексте перед переходом к базе данных (как указано Яроном в комментариях), что может быть важным фактором эффективности, если вам нужно получить один и тот же объект несколько раз, пока один и тот же контекст активен.
  • Single() — когда вы ожидаете, что запрос вернет ровно один элемент. Это вызовет исключение, если запрос не возвращает ровно один элемент.
  • SingleOrDefault() — когда вы ожидаете, что запрос вернет ноль или один элемент (т. Е. Вы не уверены, существует ли элемент с заданным ключом). Это вызовет исключение, если запрос не возвращает ноль или один элемент.
  • First() — когда вы ожидаете, что один или несколько элементов будут возвращены запросом, но вы хотите получить доступ только к первому элементу в вашем коде (порядок может быть важен в запросе здесь). Это вызовет исключение, если запрос не вернет хотя бы один элемент.
  • FirstOrDefault() — когда вы ожидаете, что запрос вернет ноль или более элементов, но вы хотите получить доступ только к первому элементу в вашем коде (т. Е. Вы не уверены, существует ли элемент с заданным ключом)

Комментарии:

1. Это зависит от сценария. Если вы знаете, что всегда должны получать одну запись из базы данных, не больше и не меньше, для данного запроса, тогда Single() является «правильным» для использования. В других ситуациях другие могут быть более подходящими. В предыдущих версиях EF мы были ограничены First() и FirstOrDefault(), которые работают для сценариев, в которых вы ожидаете одну запись, но они не предупредят вас, если вы на самом деле получите больше, чем одна запись, что может быть важно в зависимости от ситуации.

2. Спасибо. Я больше не вижу необходимости в First() , где Single() не было бы лучше. Если бы я был менее плотным, я уверен, что мог бы оценить / понять, когда использовать First() по-прежнему.

3. First() имеет наибольший смысл в случае, когда вы хотите получить только объект с самым высоким или самым низким значением из того, что вы заказываете. Например, найдите мне продажу с наибольшей общей стоимостью. Sales.OrderByDescending(s => s.TotalValue).First();

4. Во всех комментариях просматривается важное различие. Find() — это единственный метод, который выполняет поиск в контексте перед обращением к базе данных.

5. Другой момент заключается в том, что при запросе базы данных sql Single or SingleOrDefault запрашивает 2 записи (ограничение 2), в то время First как or FirstOrDefault запрашивает 1 (ограничение 1).

Ответ №2:

Я всегда склонен использовать FirstOrDefault . Если вы действительно хотите быть требовательным к производительности, вам следует использовать FirstOrDefault в EF. Under the covers SingleOrDefault использует top (2) в запросе, потому что ему нужно проверить, есть ли вторая строка, соответствующая критериям, и если это так, она выдает исключение. По сути, SingleOrDefault вы говорите, что хотите создать исключение, если ваш запрос возвращает более 1 записи.

Комментарии:

1. Вы когда-нибудь измеряли разницу в производительности между FirstOrDefault и SingleOrDefault быть значительным? Я бы сказал, что в большинстве случаев это преждевременная оптимизация.

2. Я обычно использую Single() or SingleOrDefault() , когда возвращаю что-то, из чего должен существовать только один . Причина, по которой я это делаю, заключается в том, чтобы выявлять ошибки, делая неудачно написанные запросы, которые возвращают больше, чем должны. По крайней мере, на мой взгляд, это поможет сохранить согласованность данных в системе. Конечно, это медленнее, но я бы предположил, что это не намного медленнее, и я готов заплатить эту цену.

Ответ №3:

Это действительно очень просто: Single возвращает один элемент и выдает исключение, если его нет или более одного элемента. First вернет первый элемент или выбросит, если элемента нет. FirstOrDefault вернет первый элемент или вернет значение по умолчанию ( null в случае, если данный тип является ссылочным типом), когда элемента нет.

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

Комментарии:

1. Спасибо, Стивен. Наверное, мне все еще интересно, почему вы используете одно поверх другого? Я всегда использовал FirstOrDefault(), и мне было любопытно, почему многие новые примеры, которые я видел, переключились на Single() . Есть ли причина переключиться на Single()? Есть ли другие, которые также выполняют то же самое, что я должен рассмотреть вместо этого?

2. Если вам нравится, чтобы ваш код «быстро завершался сбоем», First() и Single() позволяют вашему коду более точно указать, что ожидается (чтобы в противном случае он мог завершиться сбоем)

3. Я полностью согласен с Фрэнком. Это также касается передачи намерения. Single четко выражает, что вы ожидаете, что результат будет иметь только один элемент.

Ответ №4:

У каждого из четырех методов есть свое место; Хотя на самом деле у вас есть только две разные операции.

  • Во-первых, ожидая результирующий набор, содержащий несколько элементов, дайте мне первый элемент в этом наборе.
  • Single — Ожидая получить один результат, дайте мне этот элемент.

Версия xxxxOrDefault() просто добавляет: «Я не хочу рассматривать пустой результирующий набор как исключительное обстоятельство».

Комментарии:

1. Хорошо, мне кажется, что First() редко пригодится. Мне трудно придумать сценарий, в котором Single() не был бы первым вариантом. У вас случайно нет быстрого варианта? Спасибо.

2. К сожалению, многие разработчики используют First() или FirstOrDefault() исключительно в качестве защитной меры, думая, что это позволит избежать исключения, когда оно действительно может скрыть реальные проблемы.

Ответ №5:

С другой стороны, вы можете разделить эти методы по основной логике, например:

  • Метод будет запрашивать базу данных напрямую: Single(), SingleOrDefault(), First(), FirstOrDefault()
  • Метод выполнит поиск в кэше еще до того, как отправит запрос к базе данных: Find()

Некоторые сведения о производительности, особенно во втором случае, вы можете посмотреть здесь: https://msdn.microsoft.com/en-us/data/hh949853.aspx?f=255amp;MSPPError=-2147217396#3

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

Ответ №6:

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

Single() или First() выдают исключение, если результат не возвращается, SingleOrDefault() и FirstOrDefault() перехватывают исключение и возвращают значение null или значение по умолчанию (ResultDataType).