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

119

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

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

Спасибо.

asfsadf
источник

Ответы:

205

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

  • Find () - когда вы хотите получить предмет по первичному ключу. Это вернет null, если не сможет найти элемент. Он будет искать в контексте перед переходом к базе данных (как указал Ярон в комментариях), что может быть важным фактором эффективности, если вам нужно получить одну и ту же сущность несколько раз, пока жив один и тот же контекст.

  • Single () - когда вы ожидаете, что запрос вернет ровно один элемент. Это вызовет исключение, если запрос не вернет ровно один элемент.

  • SingleOrDefault () - когда вы ожидаете, что запросом будет возвращен ноль или один элемент (т.е. вы не уверены, существует ли элемент с заданным ключом). Это вызовет исключение, если запрос не вернет ни одного элемента.

  • First () - когда вы ожидаете, что один или несколько элементов будут возвращены запросом, но вы хотите получить доступ только к первому элементу в вашем коде (здесь порядок может быть важен в запросе). Это вызовет исключение, если запрос не вернет хотя бы один элемент.

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

Стив Уиллкок
источник
1
Это зависит от сценария. Если вы знаете, что всегда должны получать одну запись из базы данных, ни больше, ни меньше, для данного запроса, тогда Single () является «правильным» для использования. В других ситуациях другие могут быть более подходящими. В предыдущих версиях EF мы были ограничены First () и FirstOrDefault (), которые работают для сценариев, в которых вы ожидаете единственную запись, но они не будут предупреждать вас, если вы действительно получите больше, чем эта единственная запись, что может быть важно в зависимости от ситуация.
Стив Уиллкок,
1
Спасибо. Я больше не вижу, что мне нужен First (), а Single () было бы не лучше. Если бы я был менее плотным, я уверен, что смог бы оценить / понять, когда использовать First ().
asfsadf
1
First () имеет наибольший смысл в случае, когда вы хотите получить только объект с самым высоким или самым низким из того, что вы заказываете. Например, найдите мне продажу с наибольшей общей стоимостью. Sales.OrderByDescending(s => s.TotalValue).First();
Майк Чемберлен
5
Все комментарии обращают внимание на важную разницу. Find () - единственный метод, который выполняет поиск в контексте перед попаданием в базу данных.
Ярон Леви
5
Другой момент - это запрос к базе данных sql Singleили SingleOrDefaultзапрос 2 записей (ограничение 2), в то время как запрос Firstили FirstOrDefault1 (ограничение 1).
Барт Каликсто,
22

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

zeeshanhirani
источник
5
Вы когда-нибудь измеряли разницу в производительности между FirstOrDefaultи, SingleOrDefaultчтобы быть значимой? Я бы сказал, что в большинстве случаев это преждевременная оптимизация.
Стивен
Я обычно использую Single()или SingleOrDefault()возвращаю то, из чего должен существовать только один . Причина, по которой я это делаю, заключается в том, чтобы выявлять ошибки, выполняя плохо написанные запросы, которые возвращают больше, чем должны, терпят неудачу. По крайней мере, на мой взгляд, это поможет сохранить согласованность данных в системе. Конечно, это медленнее, но я предполагаю, что это не намного медленнее, и я готов заплатить эту цену.
Mortb 04
15

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

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

Стивен
источник
Спасибо, Стивен. Думаю, мне все еще интересно, почему вы использовали одно вместо другого? Я всегда использовал FirstOrDefault (), и мне было любопытно, почему многие новые примеры, которые я видел, переключились на Single (). Есть ли причина переходить на Single ()? Есть ли другие, которые также достигают того же, и я должен подумать вместо этого?
asfsadf
7
Если вам нравится, что ваш код «быстро выходит из строя»,
методы
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 () вы можете предоставить только ключ сущности для поиска.

Kryszal
источник
0

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

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

MilkTea027
источник