#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
orSingleOrDefault
запрашивает 2 записи (ограничение 2), в то времяFirst
как orFirstOrDefault
запрашивает 1 (ограничение 1).
Ответ №2:
Я всегда склонен использовать FirstOrDefault
. Если вы действительно хотите быть требовательным к производительности, вам следует использовать FirstOrDefault
в EF. Under the covers SingleOrDefault
использует top (2) в запросе, потому что ему нужно проверить, есть ли вторая строка, соответствующая критериям, и если это так, она выдает исключение. По сути, SingleOrDefault
вы говорите, что хотите создать исключение, если ваш запрос возвращает более 1 записи.
Комментарии:
1. Вы когда-нибудь измеряли разницу в производительности между
FirstOrDefault
иSingleOrDefault
быть значительным? Я бы сказал, что в большинстве случаев это преждевременная оптимизация.2. Я обычно использую
Single()
orSingleOrDefault()
, когда возвращаю что-то, из чего должен существовать только один . Причина, по которой я это делаю, заключается в том, чтобы выявлять ошибки, делая неудачно написанные запросы, которые возвращают больше, чем должны. По крайней мере, на мой взгляд, это поможет сохранить согласованность данных в системе. Конечно, это медленнее, но я бы предположил, что это не намного медленнее, и я готов заплатить эту цену.
Ответ №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).