Recuperando um único registro com LINQ

Métodos para recuperar um único registro no LINQ

O LINQ transformou o desenvolvimento em C#, proporcionando uma sintaxe poderosa para consulta e manipulação de dados. Neste artigo exploraremos os métodos do LINQ que retornam um único objeto, ideais para simplificar e melhorar a legibilidade de consultas que exigem a recuperação de um elemento específico de uma coleção. Para métodos que retornam mais de um elemento, recomendamos nosso artigo sobre “3 métodos essenciais para um desenvolvedor .NET“.

Código base para os exemplos

Para exemplificar a aplicação dos métodos, vamos utilizar como modelo de dados uma classe chamada “Produto”, cujo código é o seguinte:

				
					public class Produto
{
	public int Id { get; set; }
	public string Nome { get; set; }
	public decimal Preco { get; set; }
}

				
			

Em seguida, vamos criar uma lista chamada “produtos”, que funcionará como nossa base de dados, e adicionar cinco objetos:

				
					List<Produto> produtos = new List<Produto>
{
	new Produto { Id = 1, Nome = "Notebook", Preco = 1200 },
	new Produto { Id = 2, Nome = "Tablet", Preco = 400 },
	new Produto { Id = 3, Nome = "Smartphone", Preco = 800 },
	new Produto { Id = 4, Nome = "Monitor", Preco = 300 },
	new Produto { Id = 5, Nome = "Teclado", Preco = 50 }
};

				
			

Método First

O método “First” do LINQ é utilizado para retornar o primeiro elemento de uma sequência que satisfaz uma condição especificada. Caso nenhuma condição seja passada, ele retorna o primeiro elemento da sequência. Abaixo vemos as duas possibilidades de uso:

				
					Produto primeiroElemento = produtos.First();
Produto primeiroElementoCorrespondente = produtos.First(p => p.Preco < 500);

				
			

Nesse exemplo, a variável “primeiroElemento” receberá o produto “Notebook” que é o primeiro elemento da lista “produtos”. Já a variável “primeiroElementoCorrespondente” receberá o item “Tablet”, que é o primeiro item que possui um valor abaixo de R$ 500. Note que os itens “Monitor” e “Teclado” também possuem valor abaixo de R$ 500, mas como o método “First” encontrou um item que satisfaz a condição, ele imediatamente retorna esse item e interrompe a busca, não sendo necessário verificar os demais.

É importante notar que, se nenhum elemento da lista satisfizer a condição ou se a lista estiver vazia, o método “First” lançará uma exceção do tipo “InvalidOperationException”. Portanto, é uma boa prática usar tratamento de exceções para lidar com esses casos e evitar falhas inesperadas no programa. Isso também vale para os métodos “Single” e “Last” que vamos falar mais a frente.

Podemos implementar o seguinte código para tratar as exceções:

				
					try
{
    	Produto primeiroElementoCorrespondente = produtos.First(p => p.Preco > 2000);
}
catch (InvalidOperationException ex)
{
  	Console.WriteLine("Nenhum elemento encontrado: " + ex.Message);
}

				
			

Nesse exemplo, a lista não contém nenhum item com o preço acima de R$ 2.000. Ao tentar recuperar o primeiro elemento que corresponde a condição com “First”, uma exceção “InvalidOperationException” é lançada, que é então capturada e tratada no bloco “catch”, exibindo uma mensagem apropriada.

Método FirstOrDefault

Uma alternativa ao “First” é o método “FirstOrDefault”, que se a sequência estiver vazia ou nenhum elemento satisfizer a condição, ele retorna para tipos de referência como “string” ou objetos, o valor padrão “null” e para tipos de valor como “int”, “bool”, o valor padrão é “0” para “int” e “false” para “bool”. Isso pode ser útil para evitar a necessidade de tratamento de exceções em alguns casos:

				
					Produto primeiroElementoCorrespondente = produtos.FirstOrDefault(p => p.Preco > 2000);
				
			

Nesse exemplo, ao invés de retornar uma exceção, será retornado um valor “null”.

A partir do .NET 6, é possível definir um valor padrão diretamente no método “FirstOrDefault”, o que facilita o tratamento do retorno:

				
					Produto primeiroElementoCorrespondente = produtos.FirstOrDefault(p => p.Preco > 2000, new Produto { Id = 0, Nome = "Produto não encontrado", Preco = 0 });
				
			

Nesse exemplo, se não for encontrado um item que possua o valor acima de R$ 2.000, a variável “primeiroElementoCorrenspondente” ao invés de receber um valor “null”, ela receberá um item com “Id” e “Preco” iguais a “0” e com o “Nome” igual a “Produto não encontrado”.

Método Single

O método “Single” é bastante semelhante ao “First”. Ele também retorna um único elemento de uma sequência que satisfaz uma condição especificada. Se não for encontrado nenhum elemento que satisfaça a condição, será lançada uma exceção do tipo “InvalidOperationException”, com a mensagem “A sequência não contém nenhum elemento correspondente”. Porém, diferente do “First”, que retorna apenas o primeiro elemento caso existam múltiplos elementos que satisfaçam a condição, o “Single” vai retornar uma exceção também do tipo: “InvalidOperationException”, mas com a mensagem “A sequência contém mais de um elemento correspondente”. Ou seja, esse método deve ser usado quando se espera que exista apenas um único elemento que satisfaz a condição especificada.

				
					Produto produtoId1 = produtos.Single(p => p.Id == 1);
Produto primeiroElementoCorrespondente = produtos.Single(p => p.Preco > 500);

				
			

No exemplo acima, a variável “produtoId1” receberá o produto “Notebook”, que o único que corresponde à condição de Id == 1. Já no segundo caso, o método “Single” vai buscar um elemento que possua o valor acima de R$ 500 na lista de “produtos” e vai encontrar os itens “Notebook” e “Smartphone”. Por conta disso, uma exceção será lançada.

Método SingleOrDefault

O método “SingleOrDefault” funciona de forma semelhante ao “Single”, mas, em vez de lançar uma exceção quando nenhum elemento satisfaz a condição, ele retorna o valor padrão para o tipo especificado.

				
					Produto primeiroElementoCorrespondente = produtos.SingleOrDefault(p => p.Preco > 2000);
				
			

No exemplo acima, “primeiroElementoCorrespondente ” será “null”, pois não há nenhum elemento com o valor acima de R$ 2.000 na lista. O método “SingleOrDefault” também permite a adição de um valor padrão caso o elemento não exista na lista.

				
					Produto primeiroElementoCorrespondente = produtos.SingleOrDefault(p => p.Preco > 2000, new Produto { Id = 0, Nome = "Produto não encontrado", Preco = 0 });
				
			

Isso é útil para retornar um valor padrão para indicar a ausência de resultados. Isso evita exceções ou comportamentos inesperados na aplicação.

Método Last

O método “Last” do LINQ é utilizado para retornar o último elemento de uma sequência que satisfaz uma condição especificada. Se nenhuma condição for passada, ele retorna o último elemento da sequência. Caso nenhum elemento cumpra a condição, uma exceção do tipo “InvalidOperationException” será lançada. 

Este método é útil quando você precisa obter o elemento final de uma coleção, seja ela ordenada ou não

				
					Produto ultimoElemento = produtos.Last(p => p.Preco > 500);
				
			

Neste exemplo, a variável “ultimoElemento” receberá o valor “Smartphone”, que é o último elemento da lista que tem o valor acima de R$ 500.

Método LastOrDefault

Uma alternativa ao “Last” é o método “LastOrDefault”, que retorna o valor padrão do tipo de elemento da sequência se a sequência estiver vazia ou se nenhum elemento satisfizer a condição especificada.

				
					Produto ultimoElementoCorrespondente = produtos.LastOrDefault(p => p.Preco > 2000);
				
			

Nesse exemplo, “ultimoElementoCorrespondente” será “null”, pois não há nenhum produto na lista que tem o valor acima de R$ 2.000. 

Também é possível adicionar um valor padrão a ser retornado se a condição não for atendida:

				
					Produto primeiroElementoCorrespondente = produtos.LastOrDefault(p => p.Preco > 2000, new Produto { Id = 0, Nome = "Produto não encontrado", Preco = 0 });
				
			

Nesse exemplo, se um item com o valor acima de R$ 2.000 não for encontrado, “ultimoElementoCorrespondente” será um produto com o “Nome” “Produto não encontrado”.

Acelere a sua carreira conosco!

Se você é Desenvolvedor .NET Júnior e quer acelerar sua carreira até nível Pleno com salário de R$7k+, ou mesmo busca a primeira vaga, conheça a Mentoria .NET StartClique aqui

Se é Desenvolvedor .NET Pleno ou Sênior e quer virar referência técnica em sua equipe e mercado, com salário de R$10k+, conheça a Mentoria .NET ExpertClique aqui

Conclusão

Em suma, os métodos do LINQ para recuperação de registros únicos oferecem flexibilidade e robustez para desenvolvedores C#. O uso de métodos como “First”, “FirstOrDefault”, “Single”, “SingleOrDefault”, “Last” e “LastOrDefault” simplifica a obtenção precisa de elementos de coleções, promovendo legibilidade e eficiência no código. Contudo, é crucial entender suas diferenças e aplicabilidades específicas para evitar exceções e garantir a integridade dos dados.