this is a problem with a Ternary association....
Hibernate version:
3.0.5
Mapping documents:
Code:
<hibernate-mapping>
<class name="be.recall.db.TRecall" table="Recall" optimistic-lock="version">
<id name="id" column="RecallID" >
<generator class="increment"/>
</id>
<version name="version" type="long"/>
<property name="recallYear" column="RecallYear"></property>
[... some properties ...]
<many-to-one name="recallStatus" column="RecallStatusID" />
<!-- -->
<set name="items" table="Recall_Article_Store" lazy="true">
<key>
<column name="RecallID" ></column>
</key>
<one-to-many class="be.uchrony.recall.db.TItems" />
</set>
</class>
<class name="be.recall.db.TItems" table="Recall_Article_Store" >
<id column="ID" name="id">
<generator class="increment"></generator>
</id>
<many-to-one name="recall" column="RecallID" not-null="true" />
<many-to-one name="article" column="ArticleID" not-null="true"/>
<many-to-one name="store" column="StoreID" not-null="false"/>
<property name="quantity" column="quantity" />
<property name="deleted" column="Deleted"></property>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
Article article1 = FacadePattern.getArticle("ART12");
Article article2 = FacadePattern.getArticle("ART13");
Article article3 = FacadePattern.getArticle("ART14");
recall.addOrUpdateArticle(article1, 'P', action);
recall.addOrUpdateArticle(article2, 'P', action);
recall.addOrUpdateArticle(article3, 'P', action);
and in addOrUpdateArticle():
Code:
Items nItem = FacadePattern.getItemInstance();
nItem.setArticle(article);
nItem.setStore(item.getStore());
nItem.setUnitCode(unitCode);
nItem.setActions(action);
nItem.setDeleted(false);
nItem.setRecall(getRecall());
saveOrUpdateItem(nItem);
Full stack trace of any exception that occurs:
5:37:19,281 ERROR JDBCExceptionReporter:72 - Cannot insert the value NULL into column 'RecallID', table 'CJava_Recall_dev.dbo.Recall_Article_Store'; column does not allow nulls. UPDATE fails.
15:37:19,281 ERROR AbstractFlushingEventListener:277 - Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: could not delete collection: [be.uchrony.recall.db.TRecall.items#13]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:63)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.collection.AbstractCollectionPersister.remove(AbstractCollectionPersister.java:860)
at org.hibernate.action.CollectionRemoveAction.execute(CollectionRemoveAction.java:22)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:239)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:223)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:138)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:274)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:730)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:324)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:86)
at be.uchrony.recall.db.impl.RecallImp.saveOrUpdateItem(RecallImp.java:655)
at be.uchrony.recall.db.impl.RecallImp.saveOrUpdateArticle(RecallImp.java:594)
at be.uchrony.recall.db.impl.RecallImp.saveOrUpdateArticle(RecallImp.java:498)
at be.uchrony.recall.db.impl.RecallImp.saveOrUpdateArticle(RecallImp.java:480)
at be.uchrony.test.recall.be.uchrony.recall.RecallImp_TestCase.testsaveOrUpdateArticle(RecallImp_TestCase.java:89)
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:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:474)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:342)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:194)
The generated SQL (show_sql=true):
Hibernate: insert into Recall_Article_Store (RecallID, ArticleID, StoreID, ActionID, quantity, unitCode, ModificationDate, EncodingBy, Deleted, ID) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: update Recall set version=?, RecallYear=?, RecallNB=?, RecallVersion=?, CreateDate=?, CreateUser=?, TelephoneNumber=?, DeadLinedate=?, NotificationDate=?, Notified=?, SendDate=?, CloseDate=?, Deleted=?, NameID=?, ProblemID=?, OriginID=?, commentID=?, GlobalActionID=?, RecallStatusID=? where RecallID=? and version=?
Hibernate: update Recall_Article_Store set RecallID=null where RecallID=?
Explain :
So, has you can see, hibernate is inserting the objet, updating Recall version AND after he his setting RecallID to NULL :(
In fact :
recall.addOrUpdateArticle(article1, 'P', action);
recall.addOrUpdateArticle(article2, 'P', action);
-> ok, inserting, and updating CORRECTLY
recall.addOrUpdateArticle(article3, 'P', action);
-> error....
This is exactly the same calling, same code and article2 or article3 got exactly the same RecallID :(