Entity Framework: The instance of entity type 'User' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. Error Solution

Hello everyone! Today, I will show you the source and solution of the following error: 

An error occurred while saving changes. Error details: The instance of entity type 'Asset' 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.     

    Probably, you`ve encountered this error while deleting or updating an entity in a project uses Entity Framework. The reason behind this error is simple: Entity Framework can only track one instance of an entity with a given primary key per context. To be clear, you are trying to attach or use another instance of the same entity (naturally same primary key) in a context. 

 If you are using AutoMapper it is a common problem because AutoMapper creates another instance of the entity when mapping your DTO to database model. 

public async Task Delete(StudentDTO entity)   
{  
    StudentRepository.Delete(_mapper.Map(entity)); // Creates a new instance.   
} 

You can solve this problem in many ways. 


1-Using DeleteById instead Delete 

This is the safest and most direct approach to solve the problem. However, there is a limitation of this method, sometimes you must use whole entity and pass a DTO instead an Id. For instance Update operations, I have a solution for these cases don’t worry. 

public async Task DeleteById(int id)   
{   
var studentEntity = await studentRepository.GetById(id);                    // Don’t create new entity  
studentRepository.Delete(studentEntity);   
} 

2-Using DetachTracking 

With this method you can detach your entity from context. Therefore, there will be no error due to creating new instances but I don’t recommend this method because of Entity Frameworks tracking system. It is very complicated and complex so I will not dive in, simply it not only tracks entity’s value but also tracks the state of entity. 


private DbSet<TEntity> _entities;  
 
public void DetachTracking(int id)  
{  
var local = _context.Set<TEntity>()  
.Local.FirstOrDefault(entry => (entry as dynamic).Id == id);  

 
if (local != null)  
{  
_context.Entry(local).State = EntityState.Detached;  
}  
}   
 
public void Update(TEntity entity)  
{  
DetachTracking((entity as dynamic).Id);  
_entities.Update(entity);  
}  
 
public void Delete(TEntity entity)  
{  
DetachTracking((entity as dynamic).Id);  
_entities.Remove(entity);  
} 


3-Using NoTracking when configuring DbContext 

This is by far the simplest solution but it is not recommended because it decreases the effectiveness of Entity Framework.  

 

services.AddDbContext((provider, options) => { var connStr = configuration.GetConnectionString("Default");  
 
options.UseSqlServer(connStr, sqlOptions =>  
{  
   sqlOptions.MigrationsHistoryTable("__EFMigrationsHistory", "dbo"); })  
.UseLazyLoadingProxies()  
.EnableSensitiveDataLogging()  
.LogTo(Console.WriteLine, LogLevel.Information);  
 
options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);//We have disabled tracking across whole context.  
}); 


We’ve covered most of the suitable solutions of the following error : 

An error occurred while saving changes. Error details: The instance of entity type 'Asset' 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.     

Feel free to ask any questions. Also, I would love to see recommendations from you. 

Yorumlar