LINQ:
É mais eficiente usar o Single()
operador First()
sempre que eu tiver certeza de que a consulta retornará um único registro ?
Existe alguma diferença?
Sei que outros escreveram por que você usa um ou outro, mas pensei em ilustrar por que você NÃO deveria usar um, quando quis dizer o outro.
Nota: No meu código, eu normalmente usar FirstOrDefault()
e SingleOrDefault()
mas isso é uma questão diferente.
Tome, por exemplo, uma tabela que armazena Customers
em diferentes idiomas usando uma chave composta ( ID
, Lang
):
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).First();
Este código acima apresenta um possível erro lógico (difícil de rastrear). Ele retornará mais de um registro (supondo que você tenha o registro do cliente em vários idiomas), mas sempre retornará apenas o primeiro ... que pode funcionar algumas vezes ... mas não em outros. É imprevisível.
Como sua intenção é retornar um Customer
uso único Single()
;
O seguinte geraria uma exceção (que é o que você deseja neste caso):
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).Single();
Então, você simplesmente se bate na testa e diz para si mesmo ... OOPS! Eu esqueci o campo da linguagem! A seguir está a versão correta:
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 && c.Lang == "en" ).Single();
First()
é útil no seguinte cenário:
DBContext db = new DBContext();
NewsItem newsitem = db.NewsItems.OrderByDescending( n => n.AddedDate ).First();
Ele retornará UM objeto e, como você está usando a classificação, será o registro mais recente retornado.
Usar Single()
quando você achar que ele deve retornar sempre 1 registro explicitamente ajudará a evitar erros de lógica.
customers.Where(predicate).Single()
customers.Single(predicate)
?Single lançará uma exceção se encontrar mais de um registro que corresponda aos critérios. Primeiro sempre selecionará o primeiro registro da lista. Se a consulta retornar apenas 1 registro, você poderá prosseguir
First()
.Ambos lançarão uma
InvalidOperationException
exceção se a coleção estiver vazia. Alternativamente, você pode usarSingleOrDefault()
. Isso não emitirá uma exceção se a lista estiver vaziafonte
Solteiro()
SingleOrDefault ()
Primeiro()
FirstOrDefault ()
fonte
First
quando 1 ou mais elementos são esperados , não apenas "mais que 1" eFirstOrDefault
com qualquer quantidade de elementos.Há uma diferença sutil e semântica entre esses dois métodos.
Use
Single
para recuperar o primeiro (e único) elemento de uma sequência que deve conter um elemento e não mais. Se a sequência tiver mais do que um elemento, sua chamadaSingle
causará uma exceção, uma vez que você indicou que deveria haver apenas um elemento.Use
First
para recuperar o primeiro elemento de uma sequência que pode conter qualquer número de elementos. Se a sequência tiver mais do que um elemento, sua chamadaFirst
não causará uma exceção, uma vez que você indicou que só precisa do primeiro elemento da sequência e não se importa se existir mais.Se a sequência não contiver elementos, ambas as chamadas de método farão com que exceções sejam lançadas, pois os dois métodos esperam que pelo menos um elemento esteja presente.
fonte
Se você não deseja especificamente uma exceção lançada no caso de haver mais de um item, use
First()
.Ambos são eficientes, pegue o primeiro item.
First()
é um pouco mais eficiente, porque não se preocupa em verificar se há um segundo item.A única diferença é que
Single()
espera que exista apenas um item na enumeração e lançará uma exceção se houver mais de um. Você usa.Single()
se deseja especificamente uma exceção lançada neste caso.fonte
Se bem me lembro, Single () verifica se existe outro elemento após o primeiro (e lança uma exceção, se for o caso), enquanto First () para após obtê-lo. Ambos lançam uma exceção se a sequência estiver vazia.
Pessoalmente, eu sempre uso First ().
fonte
Com relação ao desempenho: um colega de trabalho e eu estávamos discutindo o desempenho do Single vs First (ou SingleOrDefault vs FirstOrDefault), e estava argumentando pelo ponto de que First (ou FirstOrDefault) seria mais rápido e melhoraria o desempenho (eu pretendo criar nosso aplicativo correr mais rápido).
Eu li vários posts no Stack Overflow que debatem isso. Alguns dizem que há pequenos ganhos de desempenho usando First em vez de Single. Isso ocorre porque o First retornaria o primeiro item, enquanto o Single deve varrer todos os resultados para garantir que não haja uma duplicata (ou seja: se ele encontrasse o item na primeira linha da tabela, ele ainda varria todas as outras linhas para verifique se não existe um segundo valor que corresponda à condição que, em seguida, geraria um erro). Eu senti como se estivesse em terreno sólido, com o “Primeiro” sendo mais rápido que o “Solteiro”, então decidi provar isso e encerrar o debate.
Configurei um teste no meu banco de dados e adicionei 1.000.000 de linhas de ID UniqueIdentifier Foreign UniqueIdentifier Info nvarchar (50) (preenchido com cadeias de números "0" a "999,9999"
Carreguei os dados e defini o ID como um campo de chave primária.
Usando o LinqPad, meu objetivo era mostrar que, se você pesquisasse um valor em 'Estrangeiro' ou 'Informações' usando Único, isso seria muito pior do que usar Primeiro.
Não sei explicar os resultados que obtive. Em quase todos os casos, o uso de Single ou SingleOrDefault era um pouco mais rápido. Isso não faz nenhum sentido lógico para mim, mas eu queria compartilhar isso.
Ex: usei as seguintes consultas:
Tentei consultas semelhantes no campo-chave 'Estrangeiro', que não estava indexado, pensando que o First seria mais rápido, mas o Single sempre foi um pouco mais rápido nos meus testes.
fonte
Eles são diferentes. Ambos afirmam que o conjunto de resultados não está vazio, mas único também afirma que não há mais de 1 resultado. Eu pessoalmente uso o Single nos casos em que espero apenas um resultado, apenas porque obter mais de um resultado é um erro e provavelmente deve ser tratado como tal.
fonte
Você pode tentar um exemplo simples para obter a diferença. A exceção será lançada na linha 3;
fonte
Muitas pessoas que conheço usam FirstOrDefault (), mas eu costumo usar SingleOrDefault () mais porque muitas vezes haveria algum tipo de inconsistência de dados se houvesse mais de um. Porém, isso está relacionado ao LINQ-to-Objects.
fonte
Os registros na entidade Funcionário:
Employeeid = 1
: Apenas um funcionário com esse IDFirstname = Robert
: Mais de um funcionário com esse nomeEmployeeid = 10
: Nenhum funcionário com este IDAgora é necessário entender o que
Single()
e oFirst()
significado em detalhes.Solteiro()
Single () é usado para retornar um único registro que existe exclusivamente em uma tabela; portanto, a consulta abaixo retornará o Funcionário cuja,
employeed =1
porque temos apenas um Funcionário cujaEmployeed
é 1. Se tivermos dois registrosEmployeeId = 1
, isso gera um erro (consulte a seção erro abaixo na segunda consulta para a qual estamos usando um exemploFirstname
.O exemplo acima retornará um único registro, que possui 1
employeeId
O exemplo acima lançará uma exceção porque há registros múltiplos na tabela para
FirstName='Robert'
. A exceção seráIsso, novamente, lançará uma exceção porque não existe registro para id = 10. A exceção será
Pois
EmployeeId = 10
ele retornará nulo, mas como estamos usandoSingle()
, gerará um erro. Para lidar com erro nulo, devemos usarSingleOrDefault()
.Primeiro()
First () retorna de vários registros os registros correspondentes classificados em ordem crescente, de acordo com
birthdate
o que retornará 'Robert', que é o mais antigo.Acima deve retornar o mais antigo, Robert conforme DOB.
Acima lançará uma exceção, pois não existe registro para id = 10. Para evitar uma exceção nula, devemos usar em
FirstOrDefault()
vez deFirst()
.Nota: Podemos usar somente
First()
/Single()
quando tivermos certeza absoluta de que ele não pode retornar um valor nulo.Nas duas funções, use SingleOrDefault () OR FirstOrDefault () que manipulará uma exceção nula; no caso de nenhum registro encontrado, ele retornará nulo.
fonte