These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 
Author Message
 Post subject: reassociated object has dirty collection reference
PostPosted: Sun Mar 11, 2007 8:25 pm 
Newbie

Joined: Fri Oct 20, 2006 12:55 pm
Posts: 12
Hello,

I've been trying to update an Agent class with a set of Role (s). I've :
1. read through these forums for issues related to updating entities with collections
2. I've read through the examples and hibernate tests
3. Googled this for the past 12 hours

..and still I cannot find a solution. Like many other instances, I'm sure I've just missed something simple. Here's the mappings for my classes:


<hibernate-mapping>
<class mutable="false" table="agent" name="com.mypackage.Agent">
<cache usage="nonstrict-read-write"/>
<id column="id" unsaved-value="null" access="field" name="id">
<generator class="identity"/>
</id>
<property name="passwordExpiryDate" not-null="true" access="field" column="password_expiry"/>
<property name="accountExpiryDate" not-null="true" access="field" column="account_expiry"/>
<property name="username" not-null="true" length="32" access="field" column="username" unique="true"/>
<property name="passwordHash" not-null="true" length="128" access="field" column="password_hash"/>
<property name="jobTitle" not-null="true" length="64" access="field" column="job_title"/>
<set table="agent_role" access="field" lazy="false" inverse="false" cascade="all" name="roles">
<key column="agent_id"/>
<many-to-many column="role_id" class="com.mypackage.Role"/>
</set>
<many-to-one not-null="true" column="status_id" lazy="false" access="field" cascade="none" name="status"/>
<many-to-one not-null="false" column="employer_id" lazy="false" access="field" cascade="all" name="employer"/>
<property name="secured" not-null="true" access="field" column="secured"/>
</class>
</hibernate-mapping>


<hibernate-mapping>
<class mutable="false" table="enum_role" name="com.mypackage.Role">
<cache usage="read-write"/>
<id column="id" unsaved-value="-1" access="field" name="id">
<generator class="assigned"/>
</id>
<property name="rank" not-null="true" access="field" column="rank"/>
<property name="description" not-null="true" length="64" access="field" column="description" unique="true"/>
</class>
</hibernate-mapping>

Here's the classes themselves:
/**
* @hibernate.class table="enum_role" mutable="false"
* @hibernate.cache usage="read-write"
*/
public class Role implements Serializable, Cloneable, GrantedAuthority, ConfigAttribute
{
private static final long serialVersionUID = -5383747610825163330L;

/**
* @hibernate.id column="id" generator-class="assigned" unsaved-value="-1"
*/
private long id;
/**
* @hibernate.property column="rank" not-null="true"
*/
private long rank;
/**
* @hibernate.property column="description" not-null="true" length="64" unique="true"
*/
private String description;

public Role()
{
this(-1,0,"");
}

public Role(long id, long rank, String description)
{
super();
this.id = id;
this.rank = rank;
this.description = description;
}

protected Role(Role that)
{
super();
this.id = that.id;
this.rank = that.rank;
this.description = that.description;
}

@Override
public Object clone()
{
return new Role(this);
}

// *snipped usual getters/setters*

@Override
public int hashCode()
{
final int PRIME = 31;
int result = 1;
result = PRIME * result + ((description == null) ? 0 : description.hashCode());
result = PRIME * result + (int) (id ^ (id >>> 32));
result = PRIME * result + (int) (rank ^ (rank >>> 32));
return result;
}

@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Role other = (Role) obj;
if (description == null)
{
if (other.description != null)
return false;
} else if (!description.equals(other.description))
return false;
if (id != other.id)
return false;
if (rank != other.rank)
return false;
return true;
}
}
/**
* @hibernate.class table="agent" mutable="false"
* @hibernate.cache usage="read-write"
*/
public class Agent implements Serializable, Cloneable, UserDetails
{
private static final long serialVersionUID = -2330074712527117093L;

/**
* @hibernate.id column="id" generator-class="identity" unsaved-value="null"
*/
private Long id;
/**
* @hibernate.property column="password_expiry" not-null="true"
*/
private Date passwordExpiryDate;
/**
* @hibernate.property column="account_expiry" not-null="true"
*/
private Date accountExpiryDate;
/**
* @hibernate.property column="username" not-null="true" length="32" unique="true"
*/
private String username;
/**
* @hibernate.property column="password_hash" not-null="true" length="128"
*/
private String passwordHash;
/**
* @hibernate.property column="job_title" not-null="true" length="64"
*/
private String jobTitle;
/**
* @hibernate.set inverse="false" cascade="all" table="agent_role" lazy="false"
* @hibernate.key column="agent_id"
* @hibernate.many-to-many class="com.myatmonline.beans.orm.enums.Role" column="role_id"
*/
private Set<Role> roles;
/**
* @hibernate.many-to-one column="status_id" not-null="true" cascade="none" lazy="false"
*/
private AgentStatusType status;
/**
* @hibernate.many-to-one column="employer_id" not-null="false" cascade="all" lazy="false"
*/
private Agency employer;
/**
* @hibernate.property column="secured" not-null="true"
*/
private boolean secured;

/*
* Non persistent properties, used for convenience with forms.
*/

private String passwordConfirmation;

public Agent()
{
super();

this.employer = new Agency();
this.secured = true;
}

//snipped getters and setters

/*
* End functions for Acegi security
*/

@Override
public int hashCode()
{
final int PRIME = 31;
int result = 1;
result = PRIME * result + ((accountExpiryDate == null) ? 0 : accountExpiryDate.hashCode());
result = PRIME * result + ((employer == null) ? 0 : employer.hashCode());
result = PRIME * result + ((id == null) ? 0 : id.hashCode());
result = PRIME * result + ((jobTitle == null) ? 0 : jobTitle.hashCode());
result = PRIME * result + ((passwordConfirmation == null) ? 0 : passwordConfirmation.hashCode());
result = PRIME * result + ((passwordExpiryDate == null) ? 0 : passwordExpiryDate.hashCode());
result = PRIME * result + ((passwordHash == null) ? 0 : passwordHash.hashCode());
result = PRIME * result + ((roles == null) ? 0 : roles.hashCode());
result = PRIME * result + (secured ? 1231 : 1237);
result = PRIME * result + ((status == null) ? 0 : status.hashCode());
result = PRIME * result + ((username == null) ? 0 : username.hashCode());
return result;
}

@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Agent other = (Agent) obj;
if (accountExpiryDate == null)
{
if (other.accountExpiryDate != null)
return false;
} else if (!accountExpiryDate.equals(other.accountExpiryDate))
return false;
if (employer == null)
{
if (other.employer != null)
return false;
} else if (!employer.equals(other.employer))
return false;
if (id == null)
{
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (jobTitle == null)
{
if (other.jobTitle != null)
return false;
} else if (!jobTitle.equals(other.jobTitle))
return false;
if (passwordConfirmation == null)
{
if (other.passwordConfirmation != null)
return false;
} else if (!passwordConfirmation.equals(other.passwordConfirmation))
return false;
if (passwordExpiryDate == null)
{
if (other.passwordExpiryDate != null)
return false;
} else if (!passwordExpiryDate.equals(other.passwordExpiryDate))
return false;
if (passwordHash == null)
{
if (other.passwordHash != null)
return false;
} else if (!passwordHash.equals(other.passwordHash))
return false;
if (roles == null)
{
if (other.roles != null)
return false;
} else if (!roles.equals(other.roles))
return false;
if (secured != other.secured)
return false;
if (status == null)
{
if (other.status != null)
return false;
} else if (!status.equals(other.status))
return false;
if (username == null)
{
if (other.username != null)
return false;
} else if (!username.equals(other.username))
return false;
return true;
}
}

This is the stack trace I get when calling session.update:
(entities.HibernateAgentDaoImpl 88 ) Error accessing persistent store
org.hibernate.HibernateException: reassociated object has dirty collection reference (or an array)
at org.hibernate.event.def.OnLockVisitor.processCollection(OnLockVisitor.java:66)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:101)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:61)
at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:55)
at org.hibernate.event.def.AbstractVisitor.process(AbstractVisitor.java:123)
at org.hibernate.event.def.AbstractReassociateEventListener.reassociate(AbstractReassociateEventListener.java:78)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:244)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:217)
at org.hibernate.event.def.DefaultUpdateEventListener.performSaveOrUpdate(DefaultUpdateEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireUpdate(SessionImpl.java:564)
at org.hibernate.impl.SessionImpl.update(SessionImpl.java:552)
at org.hibernate.impl.SessionImpl.update(SessionImpl.java:544)
at com.mypackage.HibernateBeanDaoImpl$11.execute(HibernateBeanDaoImpl.java:307)
at com.mypackage.AbstractHibernateBeanDao.accessStoreViaTxn(AbstractHibernateBeanDao.java:84)
at com.mypackage.HibernateBeanDaoImpl.update(HibernateBeanDaoImpl.java:304)
at com.mypackage.tests.TestHibernateUpdate.testShit1(TestHibernateUpdate.java:21)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at junit.framework.TestCase.runTest(TestCase.java:164)
at junit.framework.TestCase.runBare(TestCase.java:130)
at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:69)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:120)
at junit.framework.TestSuite.runTest(TestSuite.java:228)
at junit.framework.TestSuite.run(TestSuite.java:223)
at org.junit.internal.runners.OldTestClassRunner.run(OldTestClassRunner.java:35)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)

I could really use some help, even if it's just to a pointer on how to deal with updating collections in Hibernate. All the instances in my application are detached since I don't want to maintain any long-running conversations with the database. (I've seen a couple of forum posts that indicate this is necessary, ie maintaining the same session. Is this the case ?) I'd really appreciate any help I can get. Thank you kindly.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 12, 2007 6:09 pm 
Newbie

Joined: Fri Oct 20, 2006 12:55 pm
Posts: 12
Just for a bit more information, I'm running the following test (using Spring tests)

public class TestHibernateUpdate extends BaseSpringTestCase
{
public void testUpdate1() throws Exception
{
SessionFactory factory = (SessionFactory) super.applicationContext.getBean("wirecardSessionFactory");

Session session = factory.openSession();

Agent a = (Agent) session.get(Agent.class, new Long(3));

assertNotNull(a);

session.close();

a.getRoles().add(Role.ADMINISTRATOR);

session = factory.openSession();

session.update(a);

session.close();

}
}

And I still get the exception "reassociated object has dirty collection". Does anybody have any ideas ? Please ?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 13, 2007 12:30 am 
Expert
Expert

Joined: Tue Jan 30, 2007 12:45 am
Posts: 283
Location: India
Hi alexmarshall

Plz.. check in code that any collection which has child of parent ,have you assign to some other parent object.Might be some non session object.

_________________
Dharmendra Pandey


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 13, 2007 1:12 pm 
Newbie

Joined: Fri Oct 20, 2006 12:55 pm
Posts: 12
dharmendra.pandey wrote:
Hi alexmarshall

Plz.. check in code that any collection which has child of parent ,have you assign to some other parent object.Might be some non session object.


Hi Dharmendra,

The collection itself is only assigned to one particular instance of an Agent. The roles themselves can (and do) exist in the 'roles' collections of other Agent instances.

I just realized that my Agent class was left as mutable="false" (this was done for a good reason a long time ago and I had missed that). Even after setting mutable="true" I now have the scenario where hibernate's just not updating the relation. It's a unidirectional many-to-many association. It needs to be unidirectional because there are numerous other classes that also use the role class. I've tried using numerous permutations of the settings (cascade, cache-usage, inverse) and none of them have worked. (Yeah, I'm at the point where brute-force settings changes are around). Is there any insight you or anybody else could offer ? I'd really appreciate it. Thank you very much for your response though.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.