Thursday 25 August 2011

Hibernate Exception: "a different object with the same identifier value was already associated with the session"

I recently encountered this Hibernate exception whilst writing some routine user management functionality, and trying to save a user object back to the database.


org.hibernate.NonUniqueObjectException: A different object with the same
identifier value was already associated with the session [objectId]


I then found two potential causes of this, and by explaining them here, you should be able to check for and solve them if you're having this trouble.

The first cause is from duplicating a Hibernate object in memory, and trying to save either copy. Such as:

public void UpdateLastLogin(int userId) {

    User original = userDao.get(userId);

    User updated = new User();
    updated.setId(original.setId());
    updated.setName(original.getName());
    updated.setLastLogin(new Date());
    userDao.save(updated);
}

The user "original" is loaded into the Hibernate cache by the get() method, but then we create a new user, assign it the same primary key (ID) and try to save it. Hibernate throws a NonUniqueObjectException because "original" is still in the cache and could cause concurrency errors down the line.

The second cause of this error I have discovered comes from the Appfuse framework. Calling the genericDao.exists() method to check the presence of a key in the database actually loads it into the Hibernate cache as well. This means if you have another instance of the object due to be saved, you will invalidate it through this NonUniqueObjectException.

An example of this case could be as follows:

    
public void newEmail(User user) {
    
    boolean toSave = false;
    if(!userDao.exists(user.getUserId())) {
        toSave = true;
    } else {
        String currentEmail = userDao.getUserEmail(user.getId());
        if (!currentEmail.equals(user.getEmail())) {
            toSave = true;
        }
    }
    
    if(toSave) {
        ecmUserDao.save(user);
    }
}

So if you are getting NonUniqueObjectExceptions. Look through your code for either of these cases, and consider carefully whether you are, and whether you need to duplicate Hibernate controlled objects.