LINQ Single vs First

LINQ:

Насколько эффективнее использовать оператор Single() над First(), когда я точно знаю, что запрос вернет отдельную запись?

Есть ли разница?

Ответ 1

Если вы ожидаете одиночную запись, всегда хорошо быть явным в вашем коде.

Я знаю, что другие писали, почему вы используете то или другое, но я подумал, что я проиллюстрирую, почему вы НЕ должны использовать его, когда вы означаете другой.

Примечание. В моем коде я обычно использую FirstOrDefault() и SingleOrDefault(), но это другой вопрос.

Возьмем, например, таблицу, в которой хранятся Customers на разных языках с использованием составного ключа (ID, Lang):

DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).First();

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

Поскольку вы намерены вернуть Single Customer использовать Single();

Следующее выведет исключение (которое в этом случае вы хотите):

DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).Single();

Тогда ты просто ударишься на лоб и скажи себе... ООПС! Я забыл языковое поле! Ниже приведена правильная версия:

DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 && c.Lang == "en" ).Single();

First() полезен в следующем сценарии:

DBContext db = new DBContext();
NewsItem newsitem = db.NewsItems.OrderByDescending( n => n.AddedDate ).First();

Он вернет один объект, и поскольку вы используете сортировку, это будет самая последняя запись, которая возвращается.

Используя Single(), когда вы чувствуете, что он должен явно возвращать 1 запись, вы сможете избежать логических ошибок.

Ответ 2

Одинокий будет генерировать исключение, если он найдет более одной записи, соответствующей критериям. Сначала всегда выбирается первая запись из списка. Если запрос возвращает только 1 запись, вы можете пойти с First().

Оба будут вызывать исключение InvalidOperationException, если коллекция пуста. В качестве альтернативы вы можете использовать SingleOrDefault(). Это не вызовет исключения, если список пуст.

Ответ 3

Существует тонкая, смысловая разница между этими двумя методами.

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

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

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

Ответ 4

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

Я всегда использую First().

Ответ 5

Один()

Возвращает один конкретный элемент запроса

При использовании: если ожидается ровно 1 элемент; не 0 или более 1. Если список пуст или имеет более одного элемента, он выдает исключение "Последовательность содержит более одного элемента"

SingleOrDefault()

Возвращает один конкретный элемент запроса или значение по умолчанию, если результат не найден

При использовании: когда ожидается 0 или 1 элемент. Он выдает исключение, если в списке есть два или более элемента.

Первый()

Возвращает первый элемент запроса с несколькими результатами.

При использовании: когда ожидается 1 или более элементов, и вы хотите только первый. Он выдаст исключение, если в списке нет элементов.

FirstOrDefault()

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

При использовании: когда ожидается несколько элементов, и вы хотите только первый. Или список пуст, и вы хотите, чтобы значение по умолчанию для указанного типа было таким же, как default(MyObjectType). Например: если тип списка list<int>, он вернет первое число из списка или 0, если список пуст. Если он list<string>, он вернет первую строку из списка или null, если список пуст.

Ответ 6

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

Оба эффективны, возьмите первый элемент. First() немного эффективнее, потому что он не проверяет, есть ли второй элемент.

Единственное отличие состоит в том, что Single() ожидает, что для начала будет только один элемент в перечислении, и будет генерировать исключение, если их больше одного. Вы используете .Single(), если вы специально хотите создать исключение в этом случае.

Ответ 7

Что касается производительности: мы с коллегой обсуждали производительность Single vs First (или SingleOrDefault vs FirstOrDefault), и я спорил по тому, что First (или FirstOrDefault) будет быстрее и улучшит производительность (Im все о создании приложение работает быстрее).

Я прочитал несколько сообщений о переполнении стека, которые обсуждают это. Некоторые говорят, что есть небольшой прирост производительности, используя First вместо Single. Это потому, что First просто вернул первый элемент, а Single должен проверить все результаты, чтобы убедиться, что нет дубликата (т.е. Если он нашел элемент в первой строке таблицы, он все равно сканирует каждую другую строку, чтобы убедиться не существует второго значения, соответствующего условию, которое затем выдавало бы ошибку). Я чувствовал, что я нахожусь на твердой почве с "Первым" быстрее, чем "Одиночный", поэтому я решил доказать это и поставил дискуссию на отдых.

Я установил тест в своей базе данных и добавил 1 000 000 строк   ID UniqueIdentifier   Иностранный уникальный идентификатор   Info nvarchar (50) (заполняется строками чисел "0" до "999,9999"

Я загрузил данные и установил идентификатор в качестве поля первичного ключа.

Используя LinqPad, моя цель состояла в том, чтобы показать, что если вы искали значение в "Foreign" или "Info", используя Single, это было бы намного хуже, чем использование First.

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

Пример: я использовал следующие запросы:

var q = TestTables.First(x=>x.Info == "314638") ;
//Vs.
Var q = TestTables.Single(x=>x.Info =="314638") ; //(this was slightly faster to my surprise)

Я пробовал аналогичные запросы в поле "Foreign", которое не было проиндексировано, думая, что будет доказано, что First быстрее, но Single всегда был немного быстрее в моих тестах.

Ответ 8

Они разные. Оба они утверждают, что результирующий набор не пуст, но single также утверждает, что результат не более 1. Я лично использую Single в тех случаях, когда ожидаю, что результат будет 1, потому что получение более одного результата обратно является ошибкой и, вероятно, должно рассматриваться как таковое.

Ответ 9

Многие люди, которых я знаю, используют FirstOrDefault(), но я предпочитаю использовать SingleOrDefault() больше, потому что часто это будет некоторая несогласованность данных, если их было несколько. Однако это связано с LINQ-to-Objects.

Ответ 10

Вы можете попробовать простой пример, чтобы получить разницу. Исключение будет выбрано в строке 3;

        List<int> records = new List<int>{1,1,3,4,5,6};
        var record = records.First(x => x == 1);
        record = records.Single(x => x == 1);