Introdução
Para prosseguir com nossos estudos sobre o Entity Framework, vamos falar agora das operações básicas de select com as entidades do modelo de dados. Para seguir por esse exemplo, é necessário que você tenha lido o artigo anterior explicando como foram feitas etapas do projeto. Clique aqui para acessar o artigo inicial desta série.
Os testes unitários nesta fase do projeto não serão tão rigorosos, com inúmeras asserções e casos de falha – nosso objetivo é a praticidade e a velocidade no aprendizado. Vale lembrar que é necessário um conhecimento básico de LINQ para conseguir progredir nestes exemplos. Neste artigo vamos aprender como fazer consultas básicas com WHERE e ORDER BY.
Executando comandos SELECT simples.
Nesta série de exemplos iremos criar testes que apenas buscam dados do banco de dados. Com isso teremos uma notável sensação de economia de tempo ao ver que é possível modificar à vontade o método de acesso a dados sem ter que ficar escrevendo tediosos comandos SQL.
Vamos relembrar do artigo passado como fizemos o nosso primeiro SELECT no banco. Se você seguiu o que foi sugerido no artigo passado, o banco deverá ter 3 registros na tabela Unidade:
using System; using System.Collections.Generic; using System.Linq; using Accendis.Artigos.GerFac.DataModel.BusinessEntities; using Accendis.Artigos.GerFac.DataModel.Config; using NUnit.Framework; namespace Accendis.Artigos.GerFac.UnitTests { [TestFixture] public class UnidadeTest { [Test] public void ListarUnidades() { //Abrir uma conexão ao data model e implicitamente, abrir uma conexão com banco de dados //utilizando o Entity Framework. Utilizar o bloco using para que os recursos sejam fechados //após o termino da execução do bloco using. using (GerFacEntities entities = new GerFacEntities(AppConfiguration.ConnectionString)) { //obter as entidades do banco de dados, materializar numa lista e realizar //as operações desejadas com a lista. List unidades = (from u in entities.Unidade select u).ToList(); foreach (Unidade unidade in unidades) { Console.WriteLine(string.Format("{0} - {1}", unidade.Nome, unidade.Descricao)); } Assert.IsTrue(unidades.Count() > 0); } } } }
Vamos explicar em detalhes este método. Primeiramente, é criada uma classe do contendo o atributo [TestFixture]. Este atributo indica que esta classe poderá ter vários testes unitários. O atributo [Test] indica que o método ListarUnidades() é um teste unitário. Como regra geral, as classes de teste não podem ter construtores customizados (com parâmetros) e os métodos de teste devem ser do estilo “void-no-args”, isto é, não podem retornar nada e não devem possuir parâmetros.
O bloco using mostra criação de uma instância de uma conexão ao contexto de dados do entity framework. Seria equivalente a preparar um SqlCommand. Ele usa como parâmetro uma connection string especial (que você vê em detalhes no seu app.config do projeto de testes). Neste caso, usamos uma classe e método estático que acessa o arquivo de configuração e nos retorna os dados desejados sem grande esforço.
Dentro do bloco using, podemos montar nossa consulta utilizando LINQ à vontade. Neste caso, fizemos um comando equivalente a um SELECT * na tabela Unidade do banco de dados. Nós poderíamos ter feito uso da palavra chave “var” e rescrito a linha de comando assim:
//Não utilizar este padrão! var unidades = from u in entities.Unidade select u;
Este comando também funcionaria e então poderíamos realizar o mesmo foreach abaixo. Esta alternativa é válida em casos simples mas no caso genérico, onde é necessário retornar um objeto para as camadas superiores da aplicação, o ideal é fazer a materialização da lista chamando o método ToList(). Com uma lista formalizada, é possível realizar quais e quantas operações eu quiser.
O Entity Framework retorna as consultas do banco de dados de forma que elas sejam apenas enumeráveis uma única vez. Lembrem-se disso. Só é possível ler o resultado de uma mesma consulta uma única vez! Com a lista não – é possível ler quantas vezes quisermos. Nos códigos seguintes sempre usaremos este padrão, que é usar lista fortemente tipada e evitando ao máximo o uso do “var”. Aliás, o uso do “var” fora de consultas com LINQ é uma péssima prática de programação quando se fala em C#.
O foreach final percorre os registros recebidos e mostra na tela de resultados do plugin de testes unitários que o ReSharper oferece. Vale lembrar que esta ferramenta é opcional. E no caso geral, não é necessário imprimir os resultados de testes unitários, pois a idéia é que os mesmos sejam automáticos no futuro.
Um fato imporante é o pedaço do código: entities.Unidade – esta propriedade representa um objeto do tipo ObjectQuery. Esta classe na prática implementa IQueryable e IQueryable, que no fim das contas são as interfaces que quando implementadas fazem o trabalho de transformar queries do LINQ em comandos SQL possíveis de serem executados. Cada entidade possui uma propriedade criada de forma automática.
A última linha indica uma asserção. Todos os frameworks de testes unitários oferecem um conjunto de asserções para que o teste unitário faça a checagem se uma determinada condição é verdadeira ou falsa. Caso seja falsa, o teste falha e indica que houve uma falha de asserção.
Agora que já sabemos como é um teste unitário básico, vamos progredir com os exemplos de select simples.
[Test] public void ListarUnidadesWhere() { using (GerFacEntities entities = new GerFacEntities(AppConfiguration.ConnectionString)) { List unidades = (from u in entities.Unidade where u.Descricao == "Unidade 2" select u).ToList(); foreach (Unidade unidade in unidades) { Console.WriteLine(string.Format("{0} - {1}", unidade.Nome, unidade.Descricao)); } Assert.IsTrue(unidades.Count() == 0); unidades = entities.Unidade.Where(u => u.Nome == "Unidade 2").ToList(); foreach (Unidade unidade in unidades) { Console.WriteLine(string.Format("{0} - {1}", unidade.Nome, unidade.Descricao)); } Assert.IsTrue(unidades.Count() == 1); } }
O exemplo acima contém duas formas de se fazer uma consulta com where. A primeira usa a sintaxe chamada pela comunidade de “query syntax”, que se assemelha muito a consultas SQL comuns. A sua leitura é bem simples. A segunda consulta mostra como realizar a consulta utilizando Lambda Expressions entrada do método Where e sua sintaxe é conhecida como “fluent syntax / method syntax / full query syntax”. As consultas geradas pelo EF são as mesmas independentemente da sintaxe utilizada. Também é possível misturar sintaxes, pois no fim, o compilador analisa e monta as expressões lógicas necessárias.
Finalmente, vamos falar de ordenação e o que pode acontecer ao buscar uma única entidade do banco. Veja o teste abaixo:
[Test] public void ListarUnidadesOrderbyNull() { using (GerFacEntities entities = new GerFacEntities(AppConfiguration.ConnectionString)) { List unidades = (from u in entities.Unidade where u.Nome == "Unidade 2" orderby u.ID descending select u).ToList(); Assert.IsTrue(unidades.Count() > 0); Unidade unidadeInexistente = (from u in entities.Unidade where u.Nome == "Unidade 4" select u).First(); Assert.IsNull(unidadeInexistente); } }
A primeira consulta contém um comando de ordenação simples e passará pela primeira asserção. Já a segunda consulta irá causar a exceção já que não temos a Unidade 4 no banco. Com isso acontece a seguinte falha:
Este erro é causado pelo fato de se buscar a primeira entidade de uma lista que não contém elementos. Este erro é evitável utilizando usando o método “FirstOrDefault” no lugar de “First”. Com este método, é possível retornar valores nulos da consulta sem problemas. O método corrigido fica assim:
[Test] public void ListarUnidadesOrderbyNull() { using (GerFacEntities entities = new GerFacEntities(AppConfiguration.ConnectionString)) { List unidades = (from u in entities.Unidade where u.Nome == "Unidade 2" orderby u.ID descending select u).ToList(); Assert.IsTrue(unidades.Count() > 0); Unidade unidadeInexistente = (from u in entities.Unidade where u.Nome == "Unidade 4" select u).FirstOrDefault(); Assert.IsNull(unidadeInexistente); } }
Os comandos que buscam dados do banco podem ser mais complexos do que os exemplos acima. Porém, com o que já temos é possível realizar grande parte das buscas simples do dia-a-dia e provavelmente você estará fazendo este tipo de consulta 70% do tempo.
Encorajamos você a pesquisas os métodos que passaram a ser disponibilizados a partir da versão 3.5 do .NET. Navegue pelos métodos disponibilizados pelas entidades do modelo, tais como entidade.Unidde, entidade.Aluno e etc. Com esse background sua a experiência será cada vez maior.
No próximo artigo vamos falar sobre as operações de modificação de dados. Até já!





no comment untill now