Filtrando resultados
ResumoFiltragem restringe os resultados por critérios exatos ou faixas (ex.: faixa de preço). Implementamos filtros compondo a
IQueryableno repositório, mantendo tudo traduzido para SQL.
1. Objetivos de Aprendizagem#
- Diferenciar filtragem de busca.
- Adicionar critérios de filtro via query string.
- Compor filtros na
IQueryablesem materializar cedo.
2. Pré-requisitos#
- Paginação (Módulo 30).
3. Conceito#
Filtragem restringe por condições precisas: "produtos com preço entre 100 e 200". Difere de busca (Módulo 32), que é textual e aproximada. O porquê de compor na IQueryable: o EF Core traduz para WHERE no SQL, filtrando no banco — eficiente e sem trazer tudo para a memória.
4. Mão na Massa#
4.1. Setup#
Estenda ProdutoParameters com os campos de filtro.
4.2. Implementação Passo a Passo#
- Parâmetros de filtro:
public class ProdutoParameters : RequestParameters
{
public decimal MinPreco { get; set; }
public decimal MaxPreco { get; set; } = decimal.MaxValue;
public bool ValidPrecoRange => MaxPreco > MinPreco;
}
- Composição no repositório:
public async Task<PagedList<Produto>> GetAsync(
Guid categoriaId, ProdutoParameters p, bool trackChanges, CancellationToken ct)
{
var query = FindByCondition(x => x.CategoriaId == categoriaId, trackChanges)
.Where(x => x.Preco >= p.MinPreco && x.Preco <= p.MaxPreco)
.OrderBy(x => x.Nome);
return await PagedList<Produto>.CreateAsync(query, p.PageNumber, p.PageSize, ct);
}
- Validação no serviço:
if (!parameters.ValidPrecoRange)
throw new MaxPriceRangeBadRequestException();
4.3. Executando#
curl "http://localhost:5000/api/categorias/{catId}/produtos?minPreco=100&maxPreco=200"
5. Exemplo Completo#
Filtros se acumulam na mesma IQueryable e só são executados na materialização (CreateAsync → ToListAsync), garantindo uma única query eficiente.
6. Boas Práticas e Armadilhas#
| Faça | Evite |
|---|---|
Compor filtros na IQueryable (server-side) | ToList() antes de filtrar (client-side) |
| Validar faixas (min ≤ max) | Aceitar faixas incoerentes silenciosamente |
| Reaproveitar a query para paginação | Consultar duas vezes o banco desnecessariamente |
Atençãomaterializar com
ToList()antes doWheretraz toda a tabela para a memória e filtra na aplicação — desastre de performance. Filtre sempre noIQueryable.
7. Segurança e Produção#
- Valide e limite os valores de filtro para evitar consultas patológicas.
- Índices no banco nas colunas filtradas são essenciais para performance.
8. Exercícios#
- Fácil: adicione um filtro por categoria ativa.
- Médio: valide que
minPreco >= 0. - Desafio: construa os filtros dinamicamente conforme os parâmetros presentes, sem
ifpara cada um.
9. Resumo#
Filtragem compõe condições na IQueryable, traduzidas para WHERE no banco, com validação de faixas e execução única e eficiente.
10. Próximos Passos#
Módulo 32: busca textual, complementar à filtragem.
11. Referências#
- Microsoft Learn — Consultas com LINQ no EF Core
- Microsoft Learn — Avaliação client vs server
- Microsoft Learn — Índices no EF Core