Domine o EF Core: Guia Prático para Acesso a Dados
7 Erros Fatais no EF Core: Dicas Para Otimizar Consultas
Imagine que você tenha construído uma aplicação inteirinha com Entity Framework Core🌍 Projeto: API de E-Commerce com ASP.NET Core e SQL Server!Aprenda a construir uma API robusta para e-commerce com ASP.NET Core, EF Core, JWT e Swagger, validando suas habilidades em um projeto prático real. e, quando coloca em produção, percebe que as consultas estão lerdas, travando o sistema e deixando usuários irritados. Isso pode acontecer por vários motivos, mas existem 7 erros clássicos (e mortais!) que todo mundo comete pelo menos uma vez na vida. Vamos explorar cada um, entender o porquê deles acontecerem e, claro, como corrigir e otimizar seu código para ganhar performance.
Índice🔗
- Pecado #1: Carregar o Universo com Include Exagerado
- Pecado #2: Usar Lazy Loading sem Limites (N+1 Problem)
- Pecado #3: Falta de Paginação e Filtros
🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. Claros
- Pecado #4: Não Usar AsNoTracking quando
📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. Necessário
- Pecado #5: Ignorar a Seleção de Campos Específicos (Projeção)
- Pecado #6: Falta de Índices e
📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. Ajustes no Banco
- Pecado #7: Consultas
🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. Sincronas Gigantes (Esquecendo o Async)
Pecado #1: Carregar o Universo com Include Exagerado🔗
O uso abusivo do Include
é um clássico. Às vezes, você quer trazer dados relacionados, mas acaba incluindo tabelas e tabelas sem nem precisar. Isso gera uma consulta🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. enorme e um “carregamento do universo”.
Exemplo de como não fazer:
var pedidos = context.Pedidos
.Include(p => p.Cliente)
.Include(p => p.Cliente.Endereco)
.Include(p => p.Itens)
.ThenInclude(i => i.Produto)
.Include(p => p.Status)
.ToList();
Se você só vai exibir na tela o nome do cliente e a data do pedido, não faz sentido trazer endereço, itens e produto🔢 Operadores Aritméticos: Faça Cálculos como uma Calculadora Humana!Aprenda a dominar operadores aritméticos em C# com exemplos práticos, técnicas de cálculo e dicas para evitar erros e maximizar resultados.. Cada
Include
extra representa mais carga ao banco e📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. ao transporte de dados.
Como Resolver:
- Traga apenas os dados que você realmente vai usar.
- Considere consultas
🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. separadas quando partes dos dados são usadas em momentos diferentes.
Pecado #2: Usar Lazy Loading sem Limites (N+1 Problem)🔗
O Lazy Loading pode ser conveniente, mas é traiçoeiro: se você tem uma lista de 100 itens, e para cada item você acessa uma propriedade⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção. de navegação, o EF Core pode disparar 100 consultas extras (uma para cada item!), culminando no famoso “N+1 Problem”.
Exemplo de código problemático:
var pedidos = context.Pedidos.ToList();
foreach (var pedido in pedidos)
{
Console.WriteLine(pedido.Cliente.Nome);
// Aqui pode ocorrer uma query para cada pedido, se Lazy Loading estiver habilitado
}
Como Resolver:
- Use
Include
quando📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. precisar de dados relacionados de forma mais global.
- Prefira carregamento explícito ou carregamento ansioso controlado se o volume de dados for
🔄 Loops em C#: Repita Tarefas sem Enlouquecer (Com for e while!)Descubra como automatizar repetições em C# utilizando loops for e while com exemplos práticos que evitam erros e otimizam seu código. Aprenda mais! grande.
- Fique esperto com logs de consulta para não cair em armadilhas
🧠 Memory Management Avançado: Domine Span<T> e MemoryMarshal!Transforme seu código C# usando Span<T> e MemoryMarshal para manipulação eficiente de memória, reduzindo alocações desnecessárias e elevando a performance..
Pecado #3: Falta de Paginação e Filtros Claros🔗
Trazer milhares de registros de uma só vez pode explodir sua memória e demorar um tempão. Paginar resultados e filtrar🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. com precisão ajuda muito o banco e também a aplicação a lidar melhor com os dados.
Exemplo de paginação simples:
int pagina = 1;
int tamanhoPagina = 10;
var clientesPaginados = context.Clientes
.OrderBy(c => c.Nome)
.Skip((pagina - 1) * tamanhoPagina)
.Take(tamanhoPagina)
.ToList();
Com paginação, você economiza recursos do banco e do transporte de dados, além de melhorar a experiência🌐 LinkedIn para Devs .NET: Perfil que Atrai Recrutadores!Aprenda a otimizar seu perfil LinkedIn com dicas essenciais para devs .NET. Conquiste oportunidades e destaque suas habilidades! do usuário.
Pecado #4: Não Usar AsNoTracking quando Necessário🔗
Para buscas meramente informativas (quando não há atualização de dados), o EF Core🌍 Projeto: API de E-Commerce com ASP.NET Core e SQL Server!Aprenda a construir uma API robusta para e-commerce com ASP.NET Core, EF Core, JWT e Swagger, validando suas habilidades em um projeto prático real. não precisa manter o “tracking” de tudo em memória. Usar
AsNoTracking()
impede que cada objeto seja monitorado para alterações, melhorando bastante a performance🔄 StringBuilder: Quando Concatenar Strings Vira um Pesadelo!Descubra como o StringBuilder otimiza a concatenação em C#, evitando desperdício de memória e melhorando a performance das aplicações. Veja exemplos práticos! em cenários de leitura pesada.
var produtos = context.Produtos
.AsNoTracking()
.Where(p => p.Ativo)
.ToList();
Se a ideia é só exibir dados, não tem por que manter tracking das entidades.
Pecado #5: Ignorar a Seleção de Campos Específicos (Projeção)🔗
Muitas vezes, você só quer duas ou três colunas, mas busca a entidade inteira, com dezenas de propriedades⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção.. O EF Core tem suporte a projeção usando
Select
, que evita trazer dados desnecessários.🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio.
var listaNomesPrecos = context.Produtos
.Select(p => new { p.Nome, p.Preco })
.AsNoTracking()
.ToList();
Além de reduzir o volume de dados transferidos, isso pode aliviar o tempo de retorno do banco enormemente.
Pecado #6: Falta de Índices e Ajustes no Banco🔗
Mesmo com EF Core🌍 Projeto: API de E-Commerce com ASP.NET Core e SQL Server!Aprenda a construir uma API robusta para e-commerce com ASP.NET Core, EF Core, JWT e Swagger, validando suas habilidades em um projeto prático real., seu banco ainda precisa de uma boa modelagem e índices adequados. Se você não tiver índices nas colunas que são frequentemente usadas em
Where
ou 🔍 LINQ Básico: Filtre Dados como um Garimpeiro Digital!Descubra como o LINQ facilita o processamento de dados em C#. Filtre, ordene e transforme coleções com precisão e eficiência no seu código.
Join
, sua consulta🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. vai ser superlenta.
- Identifique colunas de pesquisa mais usadas.
- Crie índices (ou revise se o banco já criou índices automáticos).
- Monitore lentidões e
📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. use ferramentas de profiling do próprio banco.
Pecado #7: Consultas Síncronas Gigantes (Esquecendo o Async)🔗
Em aplicações modernas, usar operações assíncronas ajuda a liberar threads enquanto🔄 Loops em C#: Repita Tarefas sem Enlouquecer (Com for e while!)Descubra como automatizar repetições em C# utilizando loops for e while com exemplos práticos que evitam erros e otimizam seu código. Aprenda mais! espera a resposta do banco. Se você chamar
.ToList()
para grandes consultas🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. e não usar
.ToListAsync()
, pode travar a thread de requisição inteira, resultando em lentidão geral.
var listaProdutos = await context.Produtos
.Where(p => p.Estoque > 0)
.ToListAsync();
Com isso, seu servidor lida melhor com múltiplas requisições ao mesmo tempo e📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. evita gargalos desnecessários.
Tracking Desnecessário: O Assassino Silencioso🔗
O Crime:
var produtos = context.Produtos.ToList(); // Tracking automático!
O EF Core rastreia todas as entidades por padrão, consumindo memória e CPU mesmo em consultas🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. de apenas leitura.
A Redenção:
var produtos = context.Produtos
.AsNoTracking()
.ToList(); // Desliga o rastreamento
Impacto: Redução de até 40% no consumo de memória🔄 StringBuilder: Quando Concatenar Strings Vira um Pesadelo!Descubra como o StringBuilder otimiza a concatenação em C#, evitando desperdício de memória e melhorando a performance das aplicações. Veja exemplos práticos! em consultas grandes (Fonte: Microsoft Benchmarks
⏱️ Benchmark.NET: Meça a Velocidade do Seu Código!Aprenda a usar o Benchmark.NET para medir a performance de seu código com precisão. Descubra dicas, práticas confiáveis e evite erros comuns..
Select N+1: O Pesadelo das Queries Invisíveis🔗
O Crime:
var pedidos = context.Pedidos.ToList();
foreach (var pedido in pedidos)
{
// Gera uma nova query para cada pedido!
var cliente = context.Clientes.Find(pedido.ClienteId);
}
A Redenção:
var pedidos = context.Pedidos
.Include(p => p.Cliente) // Carrega tudo de uma vez
.ToList();
Dica: Use ThenInclude
para🔄 Loops em C#: Repita Tarefas sem Enlouquecer (Com for e while!)Descubra como automatizar repetições em C# utilizando loops for e while com exemplos práticos que evitam erros e otimizam seu código. Aprenda mais! hierarquias complexas:
.Include(p => p.Itens)
.ThenInclude(i => i.Produto)
Consultas em Loop: Quando o Laço Vira uma Corda🔗
O Crime:
foreach (var id in idsDeClientes)
{
var cliente = context.Clientes.Find(id); // 1000 ids = 1000 queries!
}
A Redenção:
var clientes = context.Clientes
.Where(c => idsDeClientes.Contains(c.Id))
.ToList(); // 1 query para todos
Impacto: Consulta🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. com 1000 IDs: 100x mais rápido ⚡
Carregar Tudo: O Hambúrguer de 10 Andares🔗
O Crime:
var clientes = context.Clientes.ToList(); // SELECT * FROM Clientes
A Redenção:
var clientes = context.Clientes
.Select(c => new
{
c.Id,
c.Nome,
c.Email
}).ToList(); // SELECT apenas colunas necessárias
Bônus: Use DTOs para consultas🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. complexas:
public class ClienteResumoDto
{
public int Id { get; set; }
public string Nome { get; set; }
}
var clientes = context.Clientes
.Select(c => new ClienteResumoDto { /* ... */ })
.ToList();
Índices Fantasmas: A Ilusão da Performance🔗
Sintomas:
- Consultas
🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. com
WHERE
,🔍 LINQ Básico: Filtre Dados como um Garimpeiro Digital!Descubra como o LINQ facilita o processamento de dados em C#. Filtre, ordene e transforme coleções com precisão e eficiência no seu código.
ORDER BY
ouJOIN
lentas - Planos de execução mostram "Table Scan"
Solução Mágica:
CREATE INDEX IX_Clientes_Email ON Clientes (Email);
modelBuilder.Entity<Cliente>()
.HasIndex(c => c.Email)
.IsUnique();
Regra de Ouro: Índices em colunas usadas em filtros, ordenações🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. e joins.
Processamento em Memória: O Disfarce de Query🔗
O Crime:
var produtos = context.Produtos
.ToList() // ⚠️ Traz TUDO para a memória!
.Where(p => p.Preco > 1000);
A Redenção:
var produtos = context.Produtos
.Where(p => p.Preco > 1000) // Filtro no SQL
.ToList();
Comparação:
Cenário | Registros no BD | Tempo |
---|---|---|
ToList + Where | 1.000.000 | 15s ⚠️ |
Where + ToList | 1.000.000 | 2s ✅ |
Paginação Ingênua: O Falso Amigo🔗
O Crime:
var page1 = context.Produtos.Skip(0).Take(10).ToList();
var page2 = context.Produtos.Skip(10).Take(10).ToList();
// ...
Problema🤝 GitHub Básico: Versionamento para Iniciantes!Descubra como o GitHub facilita colaboração, versionamento e organização de código com este tutorial prático e essencial para desenvolvedores iniciantes.:
Skip
fica mais lento conforme a página aumenta.
Solução Profissional:
var ultimoId = page1.Last().Id;
var page2 = context.Produtos
.Where(p => p.Id > ultimoId)
.Take(10)
.ToList();
Vantagem: Tempo constante ⏱️ independente da página!
Bônus: Diagnóstico de Performance
optionsBuilder.UseSqlServer(connectionString)
.LogTo(Console.WriteLine, LogLevel.Information);
2. Analise o Plano de Execução:
EXEC sp_executesql N'SELECT * FROM Clientes WHERE Id = @p0', N'@p0 int', 123
-- Clique em "Execution Plan" no SSMS
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(connectionString)
.EnableSensitiveDataLogging()
.EnableDetailedErrors());
Lembre-se: Monitorar é tão importante quanto otimizar! 🕵️♂️
No final das contas, a performance do EF Core não é uma questão mágica, mas uma soma de boas práticas🔢 Operadores Aritméticos: Faça Cálculos como uma Calculadora Humana!Aprenda a dominar operadores aritméticos em C# com exemplos práticos, técnicas de cálculo e dicas para evitar erros e maximizar resultados. de código, design de banco e monitoramento constante. Evitar esses 7 pecados já vai te colocar em um patamar bem mais tranquilo e performático!
Autor: Marcelo V. Souza - Engenheiro de Sistemas e Entusiasta em IoT e Desenvolvimento de Software, com foco em inovação tecnológica.
Referências🔗
- .NET Documentation: learn.microsoft.com/pt-br/dotnet/
- Awesome .NET: github.com/quozd/awesome-dotnet
- C# Language Specification: learn.microsoft.com/pt-br/dotnet/csharp/language-reference/language-specification/
- GitHub: Microsoft/.NET: github.com/dotnet
- Microsoft Learn: C# e .NET: learn.microsoft.com/pt-br/dotnet/csharp/