LINQ:
Является ли более эффективным использование Single()
оператора, First()
когда я точно знаю, что запрос вернет одну запись ?
Есть ли разница?
Я знаю, что другие написали, почему вы используете один или другой, но я подумал, что я бы проиллюстрировал, почему вы НЕ должны использовать один, когда вы имеете в виду другой.
Примечание: В моем коде, я обычно использую FirstOrDefault()
и , SingleOrDefault()
но это другой вопрос.
Возьмем, к примеру, таблицу, которая хранится Customers
на разных языках с помощью составного ключа ( ID
, Lang
):
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).First();
Этот код выше вводит возможную логическую ошибку (трудно отследить). Он вернет более одной записи (при условии, что у вас есть запись клиента на нескольких языках), но он всегда вернет только первую ... которая иногда может работать ... но не другие. Это непредсказуемо.
Поскольку ваше намерение состоит в том, чтобы вернуть одноразовое 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 запись, поможет вам избежать логических ошибок.
customers.Where(predicate).Single()
customers.Single(predicate)
?Single сгенерирует исключение, если найдет более одной записи, соответствующей критериям. Первая всегда выберет первую запись из списка. Если запрос возвращает только 1 запись, вы можете пойти с
First()
.Оба будут генерировать
InvalidOperationException
исключение, если коллекция пуста. В качестве альтернативы вы можете использоватьSingleOrDefault()
. Это не вызовет исключения, если список пустисточник
Не замужем()
SingleOrDefault ()
Первый()
FirstOrDefault ()
источник
First
когда ожидается 1 или более элементов , а не только «более 1» иFirstOrDefault
с любым количеством элементов.Между этими двумя методами есть тонкая семантическая разница.
Используется
Single
для извлечения первого (и единственного) элемента из последовательности, которая должна содержать один элемент и не более. Если в последовательности содержится больше одного элемента, ваш вызовSingle
вызовет исключение, поскольку вы указали, что должен быть только один элемент.Используется
First
для извлечения первого элемента из последовательности, которая может содержать любое количество элементов. Если последовательность имеет больше, чем элемент, ваш вызовFirst
не вызовет исключения, поскольку вы указали, что вам нужен только первый элемент в последовательности, и вас не волнует, существует ли больше.Если последовательность не содержит элементов, оба вызова метода вызовут исключения, поскольку оба метода ожидают присутствия хотя бы одного элемента.
источник
Если вы не хотите специально создавать исключение в случае наличия более одного элемента, используйте
First()
.Оба эффективны, возьмите первый пункт.
First()
немного более эффективен, потому что он не проверяет наличие второго элемента.Единственное отличие состоит в том,
Single()
что в начале перечисления будет только один элемент, и будет выдано исключение, если их несколько. Вы используете,.Single()
если вы хотите, чтобы в этом случае было сгенерировано исключение .источник
Если я помню, Single () проверяет, есть ли другой элемент после первого (и выдает исключение, если это так), тогда как First () останавливается после его получения. Оба выдают исключение, если последовательность пуста.
Лично я всегда использую First ().
источник
Что касается производительности: мы с коллегой обсуждали производительность Single vs First (или SingleOrDefault vs FirstOrDefault), и я спорил о том, что First (или FirstOrDefault) будет быстрее и улучшит производительность (я все о создании нашего приложения бежать быстрее).
Я прочитал несколько сообщений о переполнении стека, которые обсуждают это. Некоторые говорят, что при использовании First вместо Single наблюдается небольшой прирост производительности. Это связано с тем, что First просто вернет первый элемент, в то время как Single должен просканировать все результаты, чтобы убедиться в отсутствии дубликата (т. Е. Если он найдет элемент в первой строке таблицы, он все равно будет сканировать все остальные строки, чтобы убедитесь, что нет второго значения, соответствующего условию, которое затем выдаст ошибку). Я чувствовал, что был на твердой почве, когда «First» был быстрее, чем «Single», поэтому я решил доказать это и положить конец дискуссии.
Я настроил тест в своей базе данных и добавил 1 000 000 строк ID UniqueIdentifier Foreign UniqueIdentifier Info nvarchar (50) (заполненный строками с номерами от «0» до «999,9999»)
Я загрузил данные и установил ID в качестве поля первичного ключа.
Используя LinqPad, моя цель состояла в том, чтобы показать, что если бы вы искали значение в «Foreign» или «Info» с помощью Single, это было бы намного хуже, чем с помощью First.
Я не могу объяснить результаты, которые я получил. Почти в каждом случае использование Single или SingleOrDefault было немного быстрее. Это не имеет никакого логического смысла для меня, но я хотел поделиться этим.
Пример: я использовал следующие запросы:
Я пробовал похожие запросы в поле 'Foreign' key, которое не было проиндексировано, полагая, что First быстрее, но Single всегда немного быстрее в моих тестах.
источник
Они разные. Оба они утверждают, что набор результатов не является пустым, но одиночный также утверждает, что существует не более 1 результата. Я лично использую Single в тех случаях, когда я ожидаю, что будет только 1 результат только потому, что получение более 1 результата назад является ошибкой и, вероятно, должно рассматриваться как таковое.
источник
Вы можете попробовать простой пример, чтобы получить разницу. Исключение будет сгенерировано в строке 3;
источник
Многие люди, которых я знаю, используют FirstOrDefault (), но я склонен использовать SingleOrDefault () чаще, потому что часто это будет своего рода несогласованность данных, если их было больше одного. Это касается LINQ-to-Objects.
источник
Записи в сущности Сотрудник:
Employeeid = 1
: Только один сотрудник с этим идентификаторомFirstname = Robert
: Более одного сотрудника с таким именемEmployeeid = 10
: Нет сотрудника с таким IDТеперь необходимо понять, что
Single()
и чтоFirst()
значить в деталях.Не замужем()
Single () используется для возврата единственной записи, которая уникально существует в таблице, поэтому следующий запрос вернет сотрудника,
employeed =1
у которого только один сотрудникEmployeed
равен 1. Если у нас есть две записи,EmployeeId = 1
он выдает ошибку (см. ошибка ниже во втором запросе, где мы используем пример дляFirstname
.Выше будет возвращать одну запись, которая имеет 1
employeeId
Выше приведено исключение, потому что в таблице есть несколько записей
FirstName='Robert'
. Исключение будетЭто снова вызовет исключение, поскольку для id = 10 не существует записей. Исключение будет
Поскольку
EmployeeId = 10
это возвратит нуль, но, поскольку мы используемSingle()
это, выдаст ошибку. Для обработки нулевой ошибки мы должны использоватьSingleOrDefault()
.Первый()
First () возвращает из нескольких записей соответствующие записи, отсортированные в порядке возрастания в соответствии с
birthdate
тем, что он возвращает «Роберт», который является самым старым.Выше должен вернуть самый старый, Роберт согласно ДОБ.
Выше будет выдано исключение, так как не существует записи для id = 10. Чтобы избежать нулевого исключения, мы должны использовать
FirstOrDefault()
вместоFirst()
.Примечание: мы можем использовать только
First()
/Single()
когда мы абсолютно уверены, что он не может вернуть нулевое значение.В обеих функциях используйте SingleOrDefault () ИЛИ FirstOrDefault (), который будет обрабатывать нулевое исключение, в случае отсутствия записи он вернет ноль.
источник