Em aplicações que lidam com grandes volumes de dados, a performance é um fator crucial para garantir eficiência. O Entity Framework (EF) nos oferece soluções para o gerenciamento de dados. No entanto, quando se trata de operações que envolvem a atualização ou exclusão de um grande número de registros, o comportamento padrão do EF pode ser ineficiente, pois normalmente ele realiza essas operações de maneira individual para cada entidade.
Neste artigo vamos explorar estratégias para realizar bulk updates e bulk deletes com o Entity Framework, apresentando métodos nativos e o uso de bibliotecas externas que oferecem soluções otimizadas para cenários de alto volume de dados.
Operações de atualização padrão
O Entity Framework usa um ciclo de vida baseado no “DbContext” para rastrear as mudanças nas entidades e então enviá-las ao banco de dados. Quando você deseja atualizar várias entidades, o EF rastreia e executa as atualizações individualmente:
using (var context = new ClientesDbContext())
{
var clientes = context.Clientes.Where(c => c.Ativo).ToList();
foreach (var cliente in clientes)
{
cliente.Status = "Inativo";
}
context.SaveChanges();
}
Para cada cliente, o EF geraria um comando SQL semelhante a este:
UPDATE Clientes
SET Status = 'Inativo'
WHERE Id = 1;
Esse código funciona, mas para cada cliente atualizado, o EF enviará um comando SQL UPDATE ao banco de dados, o que pode ser muito custoso em termos de tempo.
Bulk Update e Delete
A partir do EF Core 7, está disponível o método “ExecuteUpdate”, que permite realizar atualizações em lote diretamente no banco de dados, sem a necessidade de carregar as entidades na memória. Sua sintaxe é a seguinte:
context.Clientes
.Where(c => c.Ativo)
.ExecuteUpdate(c => c.SetProperty(c => c.Status, "Inativo"));
O Entity Framework vai gerar um único comando SQL semelhante a este:
UPDATE Clientes
SET Status = 'Inativo'
WHERE Ativo = 1;
Aqui, o método “ExecuteUpdate” aplica uma atualização em todos os registros que correspondem à consulta, enviando apenas uma única operação SQL para o banco de dados, o que melhora significativamente a performance.
Para executar uma operação de exclusão em massa a estrutura é bem semelhante, bastando usar o método ExecuteDelete:
context.Clientes
.Where(c => c.Ativo)
.ExecuteDelete();
Dessa vez, a operação executada deve ser equivalente a:
DELETE FROM Clientes
WHERE Ativo = 1
Alternativa: biblioteca "EFCore.BulkExtensions"
Embora o EF Core 7 tenha melhorado significativamente o suporte para operações em lote, uma opção popular para versões anteriores ou para cenários mais avançados é usar bibliotecas como a “EFCore.BulkExtensions”. Esta biblioteca oferece suporte para bulk insert, bulk update e bulk delete com alta performance.
.NET CLI
dotnet add package EFCore.BulkExtensions
Package Manager
Install-Package EFCore.BulkExtensions
Após instalar o pacote, podemos utilizá-lo da seguinte forma:
var clientes = context.Clientes.Where(c => c.Ativo).ToList();
foreach (var cliente in clientes)
{
cliente.Status = "Inativo";
}
context.BulkUpdate(clientes);
Ao invés de chamar “SaveChanges” para salver as modificações realizadas no “cliente”, você usa o método BulkUpdate da biblioteca, que envia um único comando SQL para atualizar todos os registros.
A exclusão em massa também pode ser feita de forma semelhante:
var clientesInativos = context.Clientes.Where(c => c.Status == "Inativo").ToList();
context.BulkDelete(clientesInativos);
Conclusão
O Entity Framework, embora altamente eficiente para muitas operações, pode não ser a escolha mais otimizada para atualizações ou exclusões em grandes volumes de dados. Para esses cenários, é altamente recomendável utilizar técnicas de bulk update e bulk delete, seja com as novas funcionalidades do EF Core 7 ou com bibliotecas especializadas como EFCore.BulkExtensions.
Essas abordagens podem reduzir drasticamente o tempo de execução e o uso de recursos, garantindo que suas operações de banco de dados sejam executadas de maneira mais eficiente.