Repository template giving an exception when updating a record

advertisements

In my MVC application, I have been using Repository pattern for DAL.

Now, when I do select one entity record and and update the entity field value and do Update operation then getting below error.

Attaching an entity of type 'DAL.User' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate."} System.Exception

Below is repository stuff:

public void Update(TEntity entity)
{
    if (_context.Entry(entity).State != EntityState.Modified)
    {
         _dbSet.Attach(entity);
        _context.Entry(entity).State = EntityState.Modified;
    }
}

Calling as follow: In Bussines layer library: Manager class :

    private readonly IUnitOfWork _unitOfWork;
    private IRepository <User , int> UserRepository
    {
        get
        {
            return _unitOfWork.GetRepository<AccountUser, int>();
        }
    }
    public void UpdateUserEntity(UserDTO u)
    {
        try
        {

            User model = new User ();
            UserRepository.Update(Mapper.Map(u, model));
            _unitOfWork.SaveChanges();
        }
        catch (Exception ex)
        {
            throw;
        }
    }

Please guide me how I could resolve above error.


The exception says that there is another entity with the same key that has been attached, but different reference.

  • The exception could be caused by previous attached entity.

    db.Set<Entity>().Attach(new Entity { Id = 123 });
    db.Set<Entity>().Attach(new Entity { Id = 123 }); // different reference but same key
    
    
  • Or could be also caused by tracked entity that automatically attached.

    db.Set<Entity>().FirstOrDefault(e => e.Id == 123); // automatically attached
    db.Set<Entity>().Attach(new Entity { Id = 123 }); // different reference but same key
    
    

The second cause can be solved by mentioning AsNoTracking when retrieving item.

db.Set<Entity>().AsNoTracking().FirstOrDefault(e => e.Id == 123);

Or to be safe you can use this extension to always detach any attached entity.

public static class DbSetExtension
{
    public static void SafeAttach<T>(
        this DbContext context,
        T entity,
        Func<T, object> keyFn) where T : class
    {
        var existing = context.Set<T>().Local
            .FirstOrDefault(x => Equals(keyFn(x), keyFn(entity)));
        if (existing != null)
            context.Entry(existing).State = EntityState.Detached;

        context.Set<T>().Attach(entity);
    }
}

Usage.

db.SafeAttach(entity, e => e.Id);