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
Yorum Gönder