EF Core - Avaliação do lado do cliente


Neste artigo veremos como o EF Core se comporta na execução de consultas fazendo a avaliação no lado do cliente e do lado do servidor.

O EF Core possui alguns comportamentos padrão como:

- As consultas são diferidas ou seja são executadas quando vão ser usadas. Por isso você tem que usar o ToList() muitas vezes em suas consultas

- Por padrão o Lazy loading não esta habilitado, você tem que fazer isso explicitamente;

- Para as consultas o EF Core tem um recurso que suporta partes de uma consulta ser avaliada no servidor e partes no cliente, a decisão é conduzida pelo fato de o provedor LINQ usado poder converter a expressão em SQL ou não. (o provedor depende do banco de dados)

Neste artigo vamos focar neste último comportamento do EF Core.

Vamos analisar o seguinte cenário:

Sua aplicação possui um método para calcular o imposto :

 

     public static decimal CalculaImposto(decimal preco) => preco * 0.12m;

 

Sua aplicação utiliza o EF Core e você esta emitindo a seguinte consulta:

var produtos = context.Produtos
    .OrderBy(p => p.Preco)
    .Select(p => new
    {
        p.Id,
        p.Preco,
        Imposto = CalculaImposto(p.Preco)
    });

Vejamos como o EF Core vai se comportar ao executar essa consulta.

Nota: Por padrão, o EF Core registrará um alerta quando a avaliação do cliente for realizada

Esse comportamento pode ser transparente para o desenvolvedor mas dependendo da consulta o resultado pode impactar negativamente o desempenho da sua aplicação.

Vejamos isso considerando agora a seguinte consulta:

 

   var produtos = context.Produtos.Where(p=> CalculaImposto(p.Preco) > 50.0m);

 

Nesta consulta bem simples, temos novamente o método CalculaImposto que será avaliado no lado do cliente. Para fazer isso, o contéudo de toda a tabela Produtos vai ser colocado na memória, e, se esta tabela for muito grande isso vai afetar o desempenho da sua aplicação.

Dependendo da complexidade da consulta não é simples conhecer o que será avaliado no lado do cliente e o que será avaliado no lado do servidor, e, embora a avaliação no lado do cliente possa ser útil em alguns casos, vimos que ela pode resultar em um desempenho ruim.

Se você quiser evitar a todo o custo a avaliação do lado do cliente pode desabilitar esse recurso.

Podemos configurar para que quando a avaliação do cliente ocorrer, o comportamento seja alterado para gerar uma exeção ou para não fazer nada.

Isso pode ser feito ao configurar as opções para seu contexto, geralmente em DbContext.OnConfiguring, ou na classe Startup.cs se você estiver usando o ASP.NET Core.

Exemplo de código definido no método OnConfiguring()

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
  optionsBuilder
 
.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
}

Exemplo de código definido no método ConfigureServices da classe Startup:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<YourContext>(optionsBuilder =>
    {
      optionsBuilder
       .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Teste;Trusted_Connection=True;")
       .ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
    });
}

Com isso estamos desabilitando o recurso da avaliação ser feita no lado do cliente.

Até o próximo artigo.

"Não quero, porém, irmãos, que sejais ignorantes acerca dos que já dormem, para que não vos entristeçais, como os demais, que não têm esperança.
Porque, se cremos que Jesus morreu e ressuscitou, assim também aos que em Jesus dormem, Deus os tornará a trazer com ele."

1 Tessalonicenses 4:13,14

Referências:


José Carlos Macoratti