Back-End

1 jul, 2016

Não cometa esses erros ao utilizar o Entity Framework

Publicidade

Neste artigo vou mostrar alguns dos erros mais comuns cometidos ao se usar o Entity Framework, que é uma poderosa ferramenta ORM, que auxilia o desenvolvimento de aplicações com acesso a dados realizando o mapeamento objeto Relacional.

Como está integrado à plataforma .NET, usar o Entity Framework é muito fácil e simples, bastando mesmo alguns cliques de mouses para mapear as suas tabelas para entidades. Mas nem tudo é tão simples como parece. Existem algumas considerações e práticas que devem ser seguidas para obter um melhor rendimento e desempenho da ferramenta.

Em um outro artigo, eu apresentei dez dicas que permitem melhorar o desempenho do Entity Framework. Hoje eu apresento cinco erros muito comuns cometidos ao se usar o Entity Framework.

Verifique se você está cometendo alguns deles:

1. Está instanciado o DbContext muitas vezes?

Além disso, essa prática afeta a utilização do recurso de Cache do Entity Framework e isso se reflete no desempenho da sua aplicação. Você sabia que existe uma sobrecarga a cada vez que você instancia o objeto DbContext?

Se você está usando o Entity Framework em uma aplicação ASP  .NET MVC, é melhor usar uma única instância do DbContext por toda a duração do Request.

Solução:

  • Mantenha a mesma instância DbContext o máximo que puder.
  • Em uma aplicação ASP .NET MVC, utilize um container IoC para injetar uma única instância que exista por toda a duração do Request.

2. Está rastreando suas entidades quando não precisa disso?

Sempre que uma consulta é executada, as entidades são carregadas no rastreador de estado dos objetos. Isso é feito para rastrear quais alterações foram feitas no modelo de entidades durante a vida do contexto, de forma que uma chamada ao método SaveChanges irá realizar as consultas SQL requeridas no banco de dados. Quando consultamos entidades usando o entity framework, ele guarda as entidades no contexto, realizando o que é conhecido como tracking (rastreamento) das entidades. Ele faz isso para acompanhar o estado das entidades.

Esse é um recurso poderoso, mas ele adiciona uma sobrecarga considerável e que afeta o desempenho das consultas que são rastreadas. As consultas que não são rastreadas têm um desempenho melhor. Uma solução para isso é usar o método AsNoTracking.

O método de extensão AsNoTracking() retorna uma nova consulta e as entidades retornadas não serão armazenadas em cache pelo contexto (DbContext). Isto significa que o Entity Framework não efetua qualquer processamento ou armazenamento adicional das entidades que são devolvidos pela consulta.

Utilizar o AsNoTracking significa que as entidades serão lidas da origem de dados, mas não serão mantidas no contexto.

Nota: Não podemos atualizar estas entidades sem anexá-las ao contexto.

Solução:

  • Use o método AsNoTracking para consultas que são somente leitura.

Exemplo:

using(Entities context = new Entities())  
{  
    var funcionario = context.Funcionarios.AsNoTracking().ToList();  
}

3. Está tendo o problema Select N + 1 em suas consultas?

O EF usa, por padrão, o lazy loading; isso se você tiver definido os relacionamentos entre as suas entidades usando a palavra-chave virtual. Isto significa que os objetos relacionados não serão carregados até que eles sejam acessados pela primeira vez.

Isso parece bom à primeira vista, mas pode diminuir o desempenho das suas consultas porque realiza mais idas e vindas no banco de dados, podendo causar o problema conhecido como Select N+1 degradando a sua aplicação. Você pode impedir isso desabilitando o lazy loading.

Para mais detalhes leia aqui.

Solução:

  • Desabilite o Lazy Loading. Exemplo:
    this.configuration.ladzyloadingenabled = false;
  • Utilize o Eager Loading através do método Include. Exemplo:
using (var context = new BloggingContext()) 
{ 
    //Carrega todos os blogs e posts relacionados
      var blogs = context.Blogs 
                          .Include(b => b.Posts) 
                         .ToList(); 
}

4. Está incluindo mais campos do que precisa em suas consultas?

Às vezes, você só precisa exibir um subconjunto de dados a partir de uma entidade. Quando este for o caso, não faz sentido carregar a entidade completa do banco de dados.

Por exemplo, ao listar os clientes que você pode editar ou apagar, você não precisa carregar os campos com detalhes de endereço ou dados pessoais do cliente.

As consultas de projeção permitem que você selecione alguns campos de uma tabela de banco de dados, projetando os dados em uma entidade mais pequena.

Solução:

  • Utilize consultas projeção e restrinja os campos obtidos aos estritamente necessários.

Exemplo:

var _cliente =  (from cli in db.Clientes
                          select new {
                                cliente. Codigo,
                                cliente.Nome
                           }). ToList (); 
ao invés de :
var _cliente =  (from cli in db.Clientes
                       select cli).ToList();

5. Está executando consultas que retornam muitos resultados?

Dê uma olhada nas consultas abaixo. O que elas têm de errado?

 contexto.Posts.ToList().Where(post => post.Ativo);

  contexto.Posts.Where(post => post.Ativo).ToList();

Percebeu que elas retornam muitos resultados.

  1. A primeira consulta irá carregar todos os posts porque o método ToList() foi chamado antes do método Where;
  2. A segunda consulta vai carregar menos resultados, mas mesmo assim vai carregar mais resultados do que o esperado, pois não houve uma limitação na quantidade de posts ativados a serem retornados;

Solução:

  • Realize um filtro nas consultas antes de chamar o método ToList().
  • Limite a quantidade de resultados retornados realizando a paginação do resultado através de um método de extensão. (Na ASP .NET MVC temos o PagedList).

Exemplo:

using (UnitOfWork uow = new UnitOfWork())
            {
                IEnumerable<Blog> blogs = uow.BlogRepositorio.GetTudo();
                blogs = blogs.OrderByDescending(blog => blog.AtualizadoEm);
                IEnumerable<BlogResumoModel> lista = from blog in blogs
                                                     select new BlogResumoModel
                                                     {
                                                         Id = blog.BlogId,
                                                         Titulo = blog.Titulo,
                                                         Resumo = blog.Corpo.Length > 200 ? blog.Corpo.Substring(0, 200) : blog.Corpo,
                                                         NomeAutor = blog.Usuario.NomeUsuario,
                                                         ComentariosQuantidade = blog.Comentarios.Count(),
                                                         CriadoEm = blog.CriadoEm,
                                                         AtualizadoEm = blog.AtualizadoEm
                                                     };
                return View(lista.ToList().ToPagedList(pagina ?? 1, 2));
            }

Temos, assim, 5 dicas práticas que podem melhorar o desempenho de suas consultas com o Entity Framework.

Bom proveito!