Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Como regra geral, o Entity Framework Core tenta avaliar uma consulta no servidor o máximo possível. O EF Core converte partes da consulta em parâmetros, que podem ser avaliados no lado do cliente. O restante da consulta (juntamente com os parâmetros gerados) é dado ao provedor de banco de dados para determinar a consulta de banco de dados equivalente a ser avaliada no servidor. O EF Core dá suporte à avaliação parcial do cliente na projeção de nível superior (essencialmente, a última chamada para Select()). Se a projeção de nível superior na consulta não puder ser traduzida para o servidor, o EF Core buscará todos os dados necessários do servidor e avaliará as partes restantes da consulta no cliente. Se o EF Core detectar uma expressão, em qualquer lugar que não seja a projeção de nível superior, que não pode ser traduzida para o servidor, ela gerará uma exceção de runtime. Veja como as consultas funcionam para entender como o EF Core determina o que não pode ser traduzido para o servidor.
Observação
Antes da versão 3.0, o Entity Framework Core tinha suporte para avaliação de cliente em qualquer lugar da consulta. Para obter mais informações, consulte a seção de versões anteriores.
Dica
Você pode exibir o exemplo deste artigo no GitHub.
Avaliação do cliente na projeção de nível superior
No exemplo a seguir, um método auxiliar é usado para padronizar URLs para blogs, que são retornadas de um banco de dados do SQL Server. Como o provedor do SQL Server não tem informações sobre como esse método é implementado, não é possível traduzi-lo para o SQL. Todos os outros aspectos da consulta são avaliados no banco de dados, mas passar o retornado URL por esse método é feito no cliente.
var blogs = await context.Blogs
.OrderByDescending(blog => blog.Rating)
.Select(
blog => new { Id = blog.BlogId, Url = StandardizeUrl(blog.Url) })
.ToListAsync();
public static string StandardizeUrl(string url)
{
url = url.ToLower();
if (!url.StartsWith("http://"))
{
url = string.Concat("http://", url);
}
return url;
}
Avaliação de cliente não suportada
Embora a avaliação do cliente seja útil, isso pode resultar em um desempenho ruim às vezes. Considere a consulta a seguir, na qual o método auxiliar agora é usado em um filtro where. Como o filtro não pode ser aplicado no banco de dados, todos os dados precisam ser extraídos na memória para aplicar o filtro no cliente. Com base no filtro e na quantidade de dados no servidor, a avaliação do cliente pode resultar em um desempenho ruim. Portanto, o Entity Framework Core bloqueia essa avaliação de cliente e gera uma exceção de runtime.
var blogs = await context.Blogs
.Where(blog => StandardizeUrl(blog.Url).Contains("dotnet"))
.ToListAsync();
Avaliação explícita do cliente
Talvez seja necessário forçar a avaliação do cliente explicitamente em determinados casos, como os seguintes
- A quantidade de dados é pequena para que a avaliação no cliente não incorra em uma enorme penalidade de desempenho.
- O operador LINQ que está sendo usado não tem nenhuma tradução do lado do servidor.
Nesses casos, você pode optar explicitamente pela avaliação do cliente chamando métodos como AsEnumerable ou ToList (AsAsyncEnumerable ou ToListAsync para assíncrono). Ao usar AsEnumerable você estaria transmitindo os resultados, mas usar ToList causaria o buffer criando uma lista, que também usa memória adicional. No entanto, se você estiver enumerando várias vezes, armazenar resultados em uma lista ajuda mais, pois há apenas uma consulta no banco de dados. Dependendo do uso específico, você deve avaliar qual método é mais útil para o caso.
var blogs = context.Blogs
.AsAsyncEnumerable()
.Where(blog => StandardizeUrl(blog.Url).Contains("dotnet"))
.ToListAsync();
Dica
Se você estiver usando AsAsyncEnumerable e quiser redigir a consulta ainda mais no lado do cliente, poderá usar a biblioteca System.Interactive.Async que define operadores para enumeráveis assíncronos. Para obter mais informações, consulte Operadores LINQ do lado do cliente.
Possível vazamento de memória na avaliação do cliente
Como a tradução e a compilação de consulta são caras, o EF Core armazena em cache o plano de consulta compilado. O delegado armazenado em cache pode usar o código do cliente durante a avaliação do cliente da projeção principal. O EF Core gera parâmetros para as partes avaliadas pelo cliente da árvore e reutiliza o plano de consulta substituindo os valores de parâmetro. Mas determinadas constantes na árvore de expressão não podem ser convertidas em parâmetros. Se o delegado armazenado em cache contiver essas constantes, esses objetos não poderão ser coletados como lixo, pois ainda estão sendo referenciados. Se esse objeto contiver um DbContext ou outros serviços nele, ele poderá fazer com que o uso da memória do aplicativo cresça ao longo do tempo. Esse comportamento geralmente é um sinal de um vazamento de memória. O EF Core gera uma exceção sempre que se depara com constantes de um tipo que não podem ser mapeadas usando o provedor de banco de dados atual. As causas comuns e suas soluções são as seguintes:
- Usando um método de instância: ao usar métodos de instância em uma projeção de cliente, a árvore de expressão contém uma constante da instância. Se o método não usar dados da instância, considere tornar o método estático. Se você precisar de dados de instância no corpo do método, passe os dados específicos como um argumento para o método.
-
Passando argumentos constantes para o método: esse caso surge geralmente usando
thisem um argumento para o método cliente. Considere dividir o argumento em vários argumentos escalares, que podem ser mapeados pelo provedor de banco de dados. - Outras constantes: Se uma constante for encontrada em qualquer outro caso, você poderá avaliar se a constante é necessária no processamento. Se for necessário ter a constante ou se você não puder usar uma solução nos casos acima, crie uma variável local para armazenar o valor e usar a variável local na consulta. O EF Core converterá a variável local em um parâmetro.
Versões anteriores
A seção a seguir se aplica às versões do EF Core antes da 3.0.
Versões mais antigas do EF Core dão suporte à avaliação do cliente em qualquer parte da consulta, não apenas na projeção de nível superior. É por isso que consultas semelhantes a uma postada na seção de avaliação de cliente sem suporte funcionaram corretamente. Como esse comportamento pode causar problemas de desempenho não notados, o EF Core registrou um aviso de avaliação do cliente. Para obter mais informações sobre como visualizar o resultado do registro em log, consulte Log.
Opcionalmente, o EF Core permitiu que você alterasse o comportamento padrão para gerar uma exceção ou não fazer nada ao fazer a avaliação do cliente (exceto na projeção). O comportamento de lançamento de exceções o tornaria equivalente ao comportamento em 3.0. Para alterar o comportamento, você precisa configurar avisos ao configurar as opções para o contexto , normalmente dentro DbContext.OnConfiguringou dentro Startup.cs , se estiver usando ASP.NET Core.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFQuerying;Trusted_Connection=True;")
.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
}