steve wrote:
The message "a different object with the same identifier" really means that a different instance of an entity with the same identifier as the instance you are trying to update already existed as a persistent instance in the session. You have an instance of User which is in a transient state (the one you stored in http session). You then open a session and load a LayoutPage instance, which in turn must load (as an association) the same User entity (same id, but different instance).
When you call update on that transient instance, Hibernate is going to check whether a seperate instance of the same entity is already associated with the current session, and throw that error if true. In this case this has to be true to get that error. By locking (reassociating) the transient instance first, you avoid that problem.
For completness, you could also have called session.update(me) first and this would have worked, just as calling session.lock() after the load would also have failed.
I have studied the above over the last couple of days, trying to absorb it, since it seems to hold the key to the prolems I am having, but I am still stuck.
In my case, I have two objects, one of class QPXServerDef, the other UserPrefs. The prefs objects hold a list of server def objects, and also a reference to the currently selected server def. If I try to set the prefs' selected server to an object that is also on the prefs' list of servers, I get a NonUniqueObjectException no matter which way I try to lock() the prefs and server object or do session updates() ahead of time.
The following are simplified versions of my mapping file, class definitions and the problem code block.
Thanks in advance for any help you can give.
Yours, JonTom
Code:
<hibernate-mapping package="com.itasoftware.rfd.hibernate">
<class
name="QPXServerDef"
table="QPXServer">
<id name="ID"
column="ID"
unsaved-value="null">
<generator class="increment"/>
</id>
<property name="name"
column="QPXName"
not-null="true"/>
<many-to-one name="userPrefs" class="UserPrefs" column="UserPrefsID" not-null="false"/>
</class>
<class
name="UserPrefs"
table="UserPrefs">
<id name="ID"
column="ID"
unsaved-value="null">
<generator class="increment"/>
</id>
<many-to-one name="selectedQPXServer"
class="QPXServerDef"
column="SelectedQPXID"
cascade="all"/>
<!-- Inverse attr is not needed if QPXServerDef does not need to reference UserPrefs -->
<set name="QPXServers" inverse="true" lazy="true" cascade="all">
<key column="UserPrefsID"/>
<one-to-many class="QPXServerDef"/>
</set>
</class>
</hibernate-mapping>
public class QPXServerDef
implements Serializable
{
// Constructor
public QPXServerDef()
{
super();
sLog.trace("QPXServerDef: constructor");
}
////////////////////////////////////////////////////////////
// Property methods
public final Long getID() {
return mID;
}
public void setID(Long value) {
mID = value;
}
public final String getName() {
return mName;
}
public void setName(String value) {
mName = value;
}
public final UserPrefs getUserPrefs() {
return mUserPrefs;
}
public void setUserPrefs(UserPrefs value) {
mUserPrefs = value;
}
protected Long mID;
protected String mName;
protected UserPrefs mUserPrefs;
}
public class UserPrefs
implements Serializable
{
// Constructor
public UserPrefs()
{
super();
}
public final Long getID() {
return mID;
}
public void setID(Long value) {
mID = value;
}
public final Set getQPXServers() {
return mQPXServers;
}
public void setQPXServers(Set value) {
mQPXServers = value;
}
public final QPXServerDef getSelectedQPXServer() {
return mSelectedQPXServer;
}
public void setSelectedQPXServer(QPXServerDef value) {
mSelectedQPXServer = value;
}
protected Long mID;
private QPXServerDef mSelectedQPXServer;
private Set mQPXServers;
}
Session hibSession = null;
Transaction tx = null;
try {
hibSession = HIBUtil.newSession();
tx = hibSession.beginTransaction();
hibSession.lock(prefs, LockMode.READ);
hibSession.lock(qpxDef, LockMode.READ);
prefs.setSelectedQPXServer(qpxDef);
tx.commit();
}
catch (HibernateException except) {
HIBUtil.rollbackTx(tx);
sLog.error("HIBError: " + except.getMessage(), except);
throw new HIBException(except);
}
finally {
HIBUtil.shutSession(hibSession);
}