Hi,
I'm using Hibernate (through Spring) to save a proxied object that contains two other proxied objects. It is not clear that the use of proxies is causing complications; however, they have caused significant issues with hibernate previously.
InflationSwap is an interface to a general busness object container, and amongst other things, it contains a set of InflationSwapPay rows and another set InflationSwapRec rows. These also are interfaces to a more generic ContainerType.
My DAO code is simply:
Code:
public void save(ContainerObject containerObject) {
String interfaceName = containerObjectgetClass().getInterfaces()[0].getName();
getHibernateTemplate().saveOrUpdate(interfaceName, containerObject);
}
My hibernate mapping file is as follows (I have removed properties and simplified class names for clarity).
Code:
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping auto-import="true">
<class name="InflationSwap"
table="security_inflation_swap">
<id name="securityId" column="security_id" type="int">
<generator class="assigned" />
</id>
</property>
<set name="leg2_Row_Pay" table="security_inflation_swap_pay" cascade="all">
<key column="security_id"></key>
<one-to-many
class="InflationSwapPayRow"/>
</set>
<set name="leg1_Row_Rec" table="security_inflation_swap_rec" cascade="all">
<key column="security_id"></key>
<one-to-many
class="InflationSwapRecRow" />
</set>
</class>
<class name="InflationSwapPayRow" table="security_inflation_swap_pay">
<id name="rowNum" column="row_id" type="int" unsaved-value="0">
<generator class="sequence">
<param name="sequence">SEC_INF_SWAP_SEQ</param>
</generator>
</id>
<property name="securityId" column="security_id" type="int"></property>
</class>
<class name="InflationSwapRecRow" table="security_inflation_swap_rec">
<id name="rowNum" column="row_id" type="int" unsaved-value="0">
<generator class="sequence">
<param name="sequence">SEC_INF_SWAP_SEQ</param>
</generator>
</id>
<property name="securityId" column="security_id" type="int"></property>
</class>
This gives the following exception
Code:
org.springframework.orm.hibernate3.HibernateSystemException: a different object with the same identifier value was already associated with the session: [com.db.dbiq.calc.security.inflationswap.types.XdbInflationSwapPayRowSave#1]; nested exception is org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.db.dbiq.calc.security.inflationswap.types.XdbInflationSwapPayRowSave#1]
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:659)
at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:377)
at org.springframework.orm.hibernate3.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:697)
at com.db.dbiq.util.xdbspring.dao.XdbDAO.saveXdbObjectToDatabaseTables(XdbDAO.java:212)
at com.db.dbiq.xdb.TestInflationSwapBuilder.testPersistInflationSwap(TestInflationSwapBuilder.java:187)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:164)
at junit.framework.TestCase.runBare(TestCase.java:130)
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)
Caused by: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.db.dbiq.calc.security.inflationswap.types.XdbInflationSwapPayRowSave#1]
at org.hibernate.engine.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:587)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:284)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:223)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:89)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
at org.hibernate.engine.CascadingAction$1.cascade(CascadingAction.java:218)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:296)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:242)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:219)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
at org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:131)
at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:122)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:65)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.springframework.orm.hibernate3.HibernateAccessor.flushIfNecessary(HibernateAccessor.java:390)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:373)
... 22 more
I have tried a number of variants, including setting inverse=true and trying to save the child objects directly. The later runs, however fails to update the database. The code for that is roughly:
Code:
Set leg1 = swap.getLeg1_Row_Rec();
for (Object row : leg1) {
InflationSwapRecRow recRow = InflationSwapRecRow) row;
xdbDao.saveSubObject((SubTableRow)recRow);
}
Set leg2 = swap.getLeg2_Row_Pay();
for (Object row : leg2) {
InflationSwapPayRow recRow = (InflationSwapPayRow) row;
xdbDao.saveSubObject((SubTableRow)recRow);
}
xdbDao.closeConnection();
I have no idea how to solve this problem ATM. I would appreciate any insight anyone may have into this problem.
Thanks,