Подтвердить что ты не робот

С Entity Framework лучше использовать .First() или .Take(1) для "TOP 1"?

Мы реализуем некоторые репозитории данных EF, и у нас есть несколько запросов, которые включают TOP 1

Я прочитал много сообщений, предлагающих использовать .Take(1)
Код, который я просматриваю, использует .First()

Я понимаю, что оба они дают одинаковый результат для назначения объекта, но оба они фактически разрешают один и тот же запрос? Когда запрашивается БД, будет ли это на самом деле с TOP 1 для обоих запросов? Или они полностью выполнит запрос в перечислимый, а затем просто возьмут первую запись в коллекции?

Кроме того, если мы использовали .FirstOrDefault(), то почему мы должны ожидать какого-либо другого поведения? Я знаю, что при использовании IEnumerable вызов .First() в пустую коллекцию будет выдаваться, но если это фактически только изменение запроса для включения TOP 1, то я не должен ожидать абсолютно никакого функционального разницы между .First() и .FirstOrDefault().... правильно?

В качестве альтернативы существует ли какой-то более эффективный метод, чем эти Перечислимые расширения для выполнения запроса TOP 1?

4b9b3361

Ответ 1

От LINQPad:

С#:

age_Centers.Select(c => c.Id).First();
age_Centers.Select(c => c.Id).FirstOrDefault();
age_Centers.Select(c => c.Id).Take(1).Dump();

SQL

SELECT TOP (1) [t0].[Id]
FROM [age_Centers] AS [t0]
GO

SELECT TOP (1) [t0].[Id]
FROM [age_Centers] AS [t0]
GO

SELECT TOP (1) [t0].[Id]
FROM [age_Centers] AS [t0]

* Обратите внимание, что Take(1) перечисляет и возвращает IQueryable.

Ответ 2

Перенаправить свойство DataContext Log в Console.Out или TextFile и посмотреть, какой запрос производит каждый параметр.

Ответ 3

**First()** operates on a collection of any number of objects and returns the first object.        **Take(1)** operates on a collection of any number of objects and returns a collection containing the first object.

Вы также можете использовать Single    Single() работает с коллекцией точно одного объекта и просто возвращает объект.

Ответ 4

Сначала будет запрашиваться Take 1, поэтому нет разницы в запросе. Вызов FirstOrDefault будет одним шагом, потому что Take возвращает IEnumerable, вам нужно будет позвонить First anyway.

Сначала будет выбрано исключение, поэтому FirstOrDefault всегда предпочтительнее.

И, конечно, люди, которые написали конвертер запросов EF, достаточно умны, чтобы вызвать Take 1 вместо того, чтобы выполнять весь набор результатов и возвращать первый элемент.

Вы можете проверить это с помощью профайлера SQL.

Ответ 5

Как работает .First():

Если коллекция имеет тип IList, то к первому элементу обращается позиция индекса, которая отличается в зависимости от реализации коллекции. В противном случае итератор возвращает первый элемент.

И .Take(int count) всегда повторяется.

Если есть какой-либо выигрыш, это происходит, если коллекция реализует IList, а скорость доступа к первому элементу по индексу выше, чем для возврата итератора. Я не верю, что это будет значительным.;)

Источники:

http://www.hookedonlinq.com/FirstOperator.ashx

http://www.hookedonlinq.com/TakeOperator.ashx