Problem:
I have a one to many relationship where a user can have 1 or more Roles within the application.
The available roles already exist in the DB, therefore the relationship is to a table that just holds the userId and roleId with no updating of the role table itself.
It works correctly in the initial insert to UserRole table adding in the correct userId (value 33) and roleId (value 8), but then the subsequent update sets the userId to 33 and roleId to 0.
This is all in the same "persist" call on User object.
I don't want the second update to occur as it is not necessary.
I added the "insert="false" update="false" on many-to-one in Userrole.hbm.xml but this seems to be ignored.
Also, the logs show UserRole persisted as an entity as well as within the roles collection - what makes hibernate think it needs to persist them separately and not just within the roles collection ?
Any help is appreciated.
Hibernate version: 3.2.5
Mapping documents:
User.hbm.xml :-
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 06-Feb-2008 14:34:20 by Hibernate Tools 3.2.0.CR1 -->
<hibernate-mapping>
<class name="uk.co.acudev.valueobjects.User" table="user" catalog="acudevcart">
<meta attribute="class-code">
<![CDATA[
public boolean passwordMatch(String password)
{
if (password == null)
return false;
return this.password.equals(password);
}
public long getHighestRole()
{
java.util.Iterator iter = roles.iterator();
long roleLevel = 9999;
while(iter.hasNext())
{
UserRole iterRole = (UserRole)iter.next();
if (iterRole != null && iterRole.getRole() != null)
if (iterRole.getRole().getRoleLevel() < roleLevel)
roleLevel = iterRole.getRole().getRoleLevel();
}
return roleLevel;
}
public boolean hasRole(String role)
{
if (roles != null)
{
java.util.Iterator iter = roles.iterator();
while(iter.hasNext())
{
UserRole iterRole = (UserRole)iter.next();
if (iterRole != null && iterRole.getRole() != null)
if (iterRole.getRole().getRole().equalsIgnoreCase(role))
return true;
}
}
return false;
}
public boolean hasRoleId(String roleId)
{
if (roles != null)
{
java.util.Iterator iter = roles.iterator();
while(iter.hasNext())
{
UserRole iterRole = (UserRole)iter.next();
if (iterRole != null)
if (new Long(iterRole.getRoleId()).toString().equalsIgnoreCase(roleId))
return true;
}
}
return false;
}
public void setNewRole(String[] roleIds)
{
if (roles == null || roles.size() > 0)
roles = new ArrayList();
for (int i=0;i < roleIds.length;i++)
{
UserRole userRole = new UserRole();
userRole.setRoleId(new Long(roleIds[i]).longValue());
userRole.setUser(this);
if (this != null && this.getUserId() != null)
userRole.setUserId(this.getUserId());
roles.add(userRole);
}
}
]]>
</meta>
<id name="userId" type="java.lang.Long">
<column name="userId" />
<generator class="identity" />
</id>
<version name="version" type="long">
<column name="version" not-null="true" />
</version>
<property name="userName" type="string">
<column name="userName" length="20" not-null="true" />
</property>
<property name="password" type="string">
<column name="password" length="20" not-null="true" />
</property>
<property name="confirmPassword" type="string" insert="false" update="false">
<column name="password" length="20" not-null="false" />
</property>
<property name="userFullName" type="string">
<column name="userFullName" length="100" not-null="true" />
</property>
<property name="emailAddress" type="string">
<column name="emailAddress" length="100" not-null="false" />
</property>
<property name="homeTelNo" type="string">
<column name="homeTelNo" length="20" not-null="false" />
</property>
<property name="mobileTelNo" type="string">
<column name="mobileTelNo" length="20" not-null="false" />
</property>
<property name="workTelNo" type="string">
<column name="workTelNo" length="20" not-null="false" />
</property>
<property name="faxNo" type="string">
<column name="faxNo" length="20" not-null="false" />
</property>
<property name="preferredContactMethod" type="string">
<column name="preferredContactMethod" length="10" not-null="true" />
</property>
<property name="specialOffers" type="string">
<column name="specialOffers" length="1" not-null="false" />
</property>
<bag name="addresses" table="useraddress" lazy="true" cascade="all-delete-orphan">
<meta attribute="getPreCond">
<![CDATA[
if (addresses == null || addresses.size() == 0)
addresses.add(new Address());
]]>
</meta>
<key column="userId" not-null="true"/>
<many-to-many class="uk.co.acudev.valueobjects.Address" column="addressId"/>
</bag>
<list name="roles" lazy="false" cascade="all-delete-orphan" >
<key column="userId"/>
<list-index column="roleId"/>
<one-to-many class="uk.co.acudev.valueobjects.UserRole" />
</list>
</class>
</hibernate-mapping>
Userrole.hbm.xml :-
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 06-Feb-2008 18:50:58 by Hibernate Tools 3.2.0.CR1 -->
<hibernate-mapping>
<class name="uk.co.acudev.valueobjects.UserRole" table="userrole" catalog="acudevcart">
<id name="userId" type="java.lang.Long">
<column name="userId" />
<generator class="foreign">
<param name="property">user</param>
</generator>
</id>
<version name="version" type="long">
<column name="version" not-null="true" />
</version>
<property name="roleId" type="long">
<column name="roleId" not-null="true" />
</property>
<many-to-one name="role" update="false" insert="false" lazy="false"
column="roleId"
class="uk.co.acudev.valueobjects.Role"
cascade="none"
unique="true"
not-null="false">
</many-to-one>
<many-to-one name="user" insert="false" update="false" not-null="true"
column="userId"
class="uk.co.acudev.valueobjects.User" >
</many-to-one>
</class>
</hibernate-mapping>
Name and version of the database you are using: MySQL 4.1.9
Debug level Hibernate log excerpt:
16:07:54,934 DEBUG Printer:83 - listing entities:
16:07:54,938 DEBUG Printer:90 - uk.co.acudev.valueobjects.User{addresses=[uk.co.acudev.valueobjects.Address#23], password=adamp15, workTelNo=, userName=adamp15, userId=33, roles=[uk.co.acudev.valueobjects.UserRole#33], version=0, mobileTelNo=, homeTelNo=, preferredContactMethod=MOBILE, emailAddress=a.a@a.com, confirmPassword=adamp15, faxNo=, specialOffers=null, userFullName=adam p14}
16:07:54,948 DEBUG Printer:90 - uk.co.acudev.valueobjects.Address{county=, addressId=23, line1=, country=UK, townCity=, postcode=, line2=edne, addressType=DELIVERY}
16:07:54,950 DEBUG Printer:90 - uk.co.acudev.valueobjects.UserRole{user=uk.co.acudev.valueobjects.User#33, userId=33, role=null, roleId=8, version=0}
16:07:54,955 DEBUG AbstractFlushingEventListener:290 - executing flush
16:07:54,960 DEBUG ConnectionManager:469 - registering flush begin
16:07:54,970 DEBUG AbstractEntityPersister:2204 - Inserting entity: [uk.co.acudev.valueobjects.UserRole#33]
16:07:54,972 DEBUG AbstractEntityPersister:2206 - Version: 0
16:07:55,018 DEBUG AbstractBatcher:366 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
16:07:55,033 DEBUG SQL:401 -
/* insert uk.co.acudev.valueobjects.UserRole
*/ insert
into
acudevcart.userrole
(version, roleId, userId)
values
(?, ?, ?)
Hibernate:
/* insert uk.co.acudev.valueobjects.UserRole
*/ insert
into
acudevcart.userrole
(version, roleId, userId)
values
(?, ?, ?)
16:07:55,037 DEBUG AbstractBatcher:484 - preparing statement
16:07:55,042 DEBUG GooGooStatementCache:457 - cxnStmtMgr.statementSet( com.mysql.jdbc.Connection@18bd37a ).size(): 5
16:07:55,052 DEBUG GooGooStatementCache:196 - checkoutStatement: com.mchange.v2.c3p0.stmt.GlobalMaxOnlyStatementCache stats -- total size: 5; checked out: 1; num connections: 1; num keys: 5
16:07:55,054 DEBUG AbstractEntityPersister:1992 - Dehydrating entity: [uk.co.acudev.valueobjects.UserRole#33]
16:07:55,057 DEBUG LongType:133 - binding '0' to parameter: 1 16:07:55,060 DEBUG LongType:133 - binding '8' to parameter: 2 16:07:55,067 DEBUG LongType:133 - binding '33' to parameter: 3
16:08:02,144 DEBUG ManagerBase:677 - Start expire sessions StandardManager at 1205683682144 sessioncount 1
16:08:02,145 DEBUG ManagerBase:685 - End expire sessions StandardManager processingTime 1 expired sessions: 0
16:08:40,866 DEBUG AbstractBatcher:44 - Executing batch size: 1
16:09:02,524 DEBUG ManagerBase:677 - Start expire sessions StandardManager at 1205683742524 sessioncount 1
16:09:02,528 DEBUG ManagerBase:685 - End expire sessions StandardManager processingTime 4 expired sessions: 0
16:09:02,870 DEBUG AbstractBatcher:374 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
16:09:02,876 DEBUG AbstractBatcher:533 - closing statement
16:09:02,878 DEBUG GooGooStatementCache:271 - checkinStatement(): com.mchange.v2.c3p0.stmt.GlobalMaxOnlyStatementCache stats -- total size: 5; checked out: 0; num connections: 1; num keys: 5
16:09:02,882 DEBUG AbstractCollectionPersister:1090 - Inserting collection: [uk.co.acudev.valueobjects.User.addresses#33]
16:09:02,884 DEBUG AbstractBatcher:366 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
16:09:02,890 DEBUG SQL:401 -
/* insert collection
row uk.co.acudev.valueobjects.User.addresses */ insert
into
useraddress
(userId, addressId)
values
(?, ?)
Hibernate:
/* insert collection
row uk.co.acudev.valueobjects.User.addresses */ insert
into
useraddress
(userId, addressId)
values
(?, ?)
16:09:02,894 DEBUG AbstractBatcher:484 - preparing statement
16:09:02,899 DEBUG GooGooStatementCache:457 - cxnStmtMgr.statementSet( com.mysql.jdbc.Connection@18bd37a ).size(): 6
16:09:02,903 DEBUG GooGooStatementCache:196 - checkoutStatement: com.mchange.v2.c3p0.stmt.GlobalMaxOnlyStatementCache stats -- total size: 6; checked out: 1; num connections: 1; num keys: 6
16:09:02,906 DEBUG LongType:133 - binding '33' to parameter: 1
16:09:02,908 DEBUG LongType:133 - binding '23' to parameter: 2
16:09:02,912 DEBUG AbstractCollectionPersister:1172 - done inserting collection: 1 rows inserted
16:09:02,918 DEBUG AbstractCollectionPersister:1090 - Inserting collection: [uk.co.acudev.valueobjects.User.roles#33]
16:09:06,301 DEBUG AbstractBatcher:44 - Executing batch size: 1
16:09:06,306 DEBUG AbstractBatcher:374 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
16:09:06,311 DEBUG AbstractBatcher:533 - closing statement
16:09:06,314 DEBUG GooGooStatementCache:271 - checkinStatement(): com.mchange.v2.c3p0.stmt.GlobalMaxOnlyStatementCache stats -- total size: 6; checked out: 0; num connections: 1; num keys: 6
16:09:06,316 DEBUG AbstractBatcher:366 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
16:09:06,319 DEBUG SQL:401 -
/* create one-to-many row uk.co.acudev.valueobjects.User.roles */ update
acudevcart.userrole
set
userId=?,
roleId=?
where
userId=?
Hibernate:
/* create one-to-many row uk.co.acudev.valueobjects.User.roles */ update
acudevcart.userrole
set
userId=?,
roleId=?
where
userId=?
16:09:06,324 DEBUG AbstractBatcher:484 - preparing statement
16:09:06,328 DEBUG GooGooStatementCache:457 - cxnStmtMgr.statementSet( com.mysql.jdbc.Connection@18bd37a ).size(): 7
16:09:06,331 DEBUG GooGooStatementCache:196 - checkoutStatement: com.mchange.v2.c3p0.stmt.GlobalMaxOnlyStatementCache stats -- total size: 7; checked out: 1; num connections: 1; num keys: 7
16:09:06,336 DEBUG LongType:133 - binding '33' to parameter: 1 16:09:06,339 DEBUG IntegerType:133 - binding '0' to parameter: 2 16:09:06,341 DEBUG LongType:133 - binding '33' to parameter: 3
16:09:06,344 DEBUG AbstractCollectionPersister:1172 - done inserting collection: 1 rows inserted
16:10:02,851 DEBUG ManagerBase:677 - Start expire sessions StandardManager at 1205683802851 sessioncount 1
|