O erro "The instance of entity type 'X' cannot be tracked because another instance with the same key value is already being tracked" é uma das exceçÔes mais comuns e frustrantes no Entity Framework Core. Vamos entender por que ela acontece e como resolver de vez.
VocĂȘ estĂĄ lĂĄ, programando tranquilamente. O cĂłdigo faz sentido, as entidades estĂŁo configuradas, as relaçÔes parecem corretas. VocĂȘ chama SaveChangesAsync() e... BUM. Uma exceção que parece vir do nada.
O erro que vamos resolver hoje Ă© este:
System.InvalidOperationException:
The instance of entity type 'Produto' cannot be tracked because another instance
with the same key value for {'Id'} is already being tracked.
When attaching existing entities, ensure that only one entity instance
with a given key value is attached.
Esse erro jĂĄ me tirou do sĂ©rio mais vezes do que eu gostaria de admitir. Mas, com o tempo, aprendi que ele tem causas bem especĂficas â e soluçÔes igualmente especĂficas.
O cenĂĄrio que causa o erro: um exemplo prĂĄtico
Imagine o seguinte cenĂĄrio: vocĂȘ tem uma entidade Produto, recebe uma atualização via API, e tenta salvar no banco.
A entidade:
public class Produto
{
public int Id { get; set; }
public string Nome { get; set; }
public decimal Preco { get; set; }
public int CategoriaId { get; set; }
public Categoria Categoria { get; set; }
}
O cĂłdigo problemĂĄtico:
[HttpPut("{id}")]
public async Task AtualizarProduto(int id, Produto produtoAtualizado)
{
// 1. Carrega o produto existente
var produtoExistente = await _context.Produtos
.Include(p => p.Categoria)
.FirstOrDefaultAsync(p => p.Id == id);
// 2. Tenta atualizar os valores
produtoExistente.Nome = produtoAtualizado.Nome;
produtoExistente.Preco = produtoAtualizado.Preco;
produtoExistente.Categoria = produtoAtualizado.Categoria; // <- PROBLEMA AQUI!
// 3. Salva
await _context.SaveChangesAsync(); // BUM! Exceção de tracking!
}
Quando a requisição chega, o produtoAtualizado contém uma instùncia de Categoria com o mesmo Id que jå estå sendo rastreada pelo produtoExistente (que foi carregado com Include()). O EF Core entra em conflito: duas instùncias diferentes da mesma entidade com a mesma chave.
? ERRO: System.InvalidOperationException:
The instance of entity type 'Categoria' cannot be tracked because another instance
with the key value '{Id: 5}' is already being tracked.
Solução 1: Atualize a entidade rastreada, não a instùncia recebida
Em vez de anexar a instĂąncia recebida, carregue a entidade original do banco e atualize suas propriedades.
[HttpPut("{id}")]
public async Task AtualizarProduto(int id, Produto produtoAtualizado)
{
// 1. Carrega o produto do banco
var produtoExistente = await _context.Produtos
.Include(p => p.Categoria)
.FirstOrDefaultAsync(p => p.Id == id);
if (produtoExistente == null)
return NotFound();
// 2. Atualiza APENAS as propriedades que vieram na requisição
// NĂO atribui a Categoria inteira â apenas o Id
produtoExistente.Nome = produtoAtualizado.Nome;
produtoExistente.Preco = produtoAtualizado.Preco;
produtoExistente.CategoriaId = produtoAtualizado.CategoriaId;
// 3. Salva
await _context.SaveChangesAsync();
return Ok(produtoExistente);
}
? SUCESSO: Produto atualizado com sucesso! Nenhum conflito de tracking porque usamos a mesma instĂąncia rastreada.
Solução 2: Use AsNoTracking() para consultas que não vão modificar dados
Se vocĂȘ sĂł precisa ler dados e nĂŁo vai modificĂĄ-los, use AsNoTracking(). Isso impede que o DbContext rastreie a entidade.
// Consulta para exibição (NĂO vai modificar) public async Task> ListarProdutos() { // AsNoTracking() previne tracking desnecessĂĄrio return await _context.Produtos .AsNoTracking() .Include(p => p.Categoria) .ToListAsync(); }
? SUCESSO: 150 produtos retornados. Nenhuma entidade foi rastreada. MemĂłria otimizada!
Solução 3: Detach + Update para substituir a entidade
Se vocĂȘ sabe que a entidade rastreada estĂĄ desatualizada e quer substituĂ-la completamente, pode desanexar a antiga e anexar a nova.
public async Task SubstituirProduto(Produto produtoNovo)
{
// 1. Verifica se a entidade jĂĄ estĂĄ sendo rastreada
var entrada = _context.Entry(produtoNovo);
if (entrada.State != EntityState.Detached)
{
// 2. Desanexa a entidade antiga
entrada.State = EntityState.Detached;
Console.WriteLine($"?? Entidade {produtoNovo.Id} desanexada.");
}
// 3. Anexa como modificada
_context.Update(produtoNovo);
Console.WriteLine($"?? Entidade {produtoNovo.Id} anexada como Modified.");
// 4. Salva
await _context.SaveChangesAsync();
Console.WriteLine($"? Produto {produtoNovo.Id} salvo com sucesso!");
}
?? Entidade 42 desanexada. ?? Entidade 42 anexada como Modified. ? Produto 42 salvo com sucesso!
Solução 4: CurrentValues.SetValues() â a abordagem mais segura
Esta é a abordagem recomendada para cenårios de atualização. Ela copia os valores da instùncia recebida para a instùncia rastreada sem conflitos.
public async Task AtualizarProdutoComSetValues(Produto produtoAtualizado)
{
// 1. Carrega a entidade rastreada
var produtoOriginal = await _context.Produtos
.FirstOrDefaultAsync(p => p.Id == produtoAtualizado.Id);
if (produtoOriginal == null)
{
Console.WriteLine($"? Produto {produtoAtualizado.Id} nĂŁo encontrado.");
return;
}
Console.WriteLine($"?? Produto original: {produtoOriginal.Nome} (R$ {produtoOriginal.Preco})");
// 2. Aplica os novos valores Ă instĂąncia rastreada
_context.Entry(produtoOriginal).CurrentValues.SetValues(produtoAtualizado);
Console.WriteLine($"?? Valores atualizados: {produtoAtualizado.Nome} (R$ {produtoAtualizado.Preco})");
// 3. Salva
await _context.SaveChangesAsync();
Console.WriteLine($"? Produto {produtoOriginal.Id} atualizado com sucesso!");
}
?? Produto original: Teclado MecĂąnico (R$ 350,00) ?? Valores atualizados: Teclado MecĂąnico RGB (R$ 399,00) ? Produto 42 atualizado com sucesso!
Como diagnosticar: habilitando logs sensitivos
A prĂłpria Microsoft recomenda ativar o EnableSensitiveDataLogging para ver quais chaves estĂŁo causando conflito.
// Configure no DbContext
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer("Server=localhost;Database=MeuDB;")
.EnableSensitiveDataLogging() // ATENĂĂO: APENAS EM DESENVOLVIMENTO!
.LogTo(Console.WriteLine);
}
// Agora a mensagem de erro mostra o valor exato:
// "The instance of entity type 'Categoria' cannot be tracked because
// another instance with the key value '{Id: 5}' is already being tracked."
?? Atenção
Ative o logging sensitivo apenas em desenvolvimento. Nunca em produção, pois ele pode expor dados sensĂveis como senhas e chaves privadas.
Resumo rĂĄpido: o que fazer quando o erro aparecer
| Situação | Solução |
|---|---|
| Consulta apenas para leitura | AsNoTracking() |
| Atualização com objeto recebido | CurrentValues.SetValues() |
| Substituição completa | Detach + Update |
| Conflito de navegação | Atualize apenas o Id da navegação |
| DiagnĂłstico | EnableSensitiveDataLogging() |
O sistema de tracking do Entity Framework Core Ă© uma das suas maiores vantagens. Mas, como toda ferramenta poderosa, exige cuidado. O erro "instance cannot be tracked" Ă© um sinal de que vocĂȘ estĂĄ tentando usar o DbContext de forma inconsistente.
Com as soluçÔes que mostrei aqui, vocĂȘ vai gastar menos tempo debugando e mais tempo construindo coisas incrĂveis.
E vocĂȘ, jĂĄ passou por esse erro? Deixe seu comentĂĄrio contando como resolveu â sua experiĂȘncia pode ajudar outros devs.
Quer mais dicas de C# e .NET?
No Nerd Cult, acreditamos que cĂłdigo de qualidade resolve problemas reais. Assine nossa newsletter e receba conteĂșdos sobre desenvolvimento, carreira e cultura geek.

Livros sobre C# e .Net Core
O melhor conteĂșdo para o aprendizado da linguagem.
Quer contribuir com este blog?
Adoramos ouvir a opiniĂŁo dos nossos leitores! VocĂȘ jĂĄ passou por esse erro no EF Core? Como vocĂȘ resolveu? Deixe seu comentĂĄrio abaixo com sua experiĂȘncia â suas dicas podem ajudar outros devs na mesma situação. Sugira novos temas que vocĂȘ gostaria de ver no Nerd Cult â e se vocĂȘ quiser ver seu prĂłprio post publicado aqui, entre em contato conosco! Estamos sempre abertos a colaboraçÔes e histĂłrias inspiradoras da nossa comunidade.
Nerd Cult â onde o cĂłdigo encontra o rock, o cinema e a cultura geek. Porque ser nerd Ă© transformar o medo em curiosidade, e a curiosidade em poder.
#EntityFrameworkCore #CSharp #DotNet #Desenvolvimento #NerdCult
ComentĂĄrios (0)
Nenhum comentĂĄrio ainda. Seja o primeiro a comentar!
Adicionar ComentĂĄrio