First, I apologize if this is a bit long.
I have a very strange problem with list indexing that produces errors only in certain circumstances. One of them is: I have a tree in an application, your typical tree where there's 1 parent and many children, like a file-system tree for example. The relationship should be clear there.
The children are indexed, so that if the user moves any items around in the tree, next time they load the application they will be in the same location as when they last saw them. The problem appears when I try to add new children to parents. Oddly enough, adding a child to the "root" of the tree always works the first time, any subsequent additions to the same folder fails.
Hibernate version:
3.2.5
Mapping documents:
hibernate-mapping.hbm.xml;
Code:
<class name="TreeNode" table="TreeNode" discriminator-value="TreeNode" batch-size="10" lazy="false">
<cache usage="read-write"/>
<id name="ID" type="string">
<column name="ID" sql-type="char(40)"/>
<generator class="assigned"/>
</id>
<discriminator type="string">
<column name="CLASS" sql-type="varchar(150)" index="TreeNode_CLASS_IDX"/>
</discriminator>
<version column="DBVERSION" name="DBVERSION" type="integer" unsaved-value="null"/>
<list name="ChildNodes" cascade="all" fetch="select" lazy="true">
<cache usage="read-write"/>
<key>
<column name="TreeNodeID" sql-type="char(40)"/>
</key>
<index>
<column name="POSITION" not-null="true"/>
</index>
<one-to-many class="TreeNode"/>
</list>
<list name="Permissions" cascade="all" fetch="select" lazy="true">
<cache usage="read-write"/>
<key>
<column name="TreeNodeID" sql-type="char(40)"/>
</key>
<index>
<column name="POSITION" not-null="true"/>
</index>
<one-to-many class="Permission"/>
</list>
<property name="UseDefaultPermissions" type="boolean">
<column name="UseDefaultPermissions" not-null="false" unique="false" sql-type="smallint(1) default 1"/>
</property>
<many-to-one name="Owner" class="User" cascade="save-update" fetch="select">
<column name="OwnerID" sql-type="char(40)"/>
</many-to-one>
<property name="Name" type="string">
<column name="Name" not-null="false" unique="false" sql-type="varchar(150)"/>
</property>
<property name="Modified" type="timestamp">
<column name="Modified" sql-type="datetime" not-null="false" unique="false"/>
</property>
<property name="Created" type="timestamp">
<column name="Created" sql-type="datetime" not-null="false" unique="false"/>
</property>
<subclass name="Folder" discriminator-value="Folder" lazy="false">
</subclass>
<subclass name="Project" discriminator-value="Project" lazy="false">
<list name="Questions" cascade="all" fetch="select" lazy="true">
<cache usage="read-write"/>
<key>
<column name="ProjectID" sql-type="char(40)"/>
</key>
<index>
<column name="POSITION" not-null="true"/>
</index>
<one-to-many class="Question"/>
</list>
<list name="Phases" cascade="all" fetch="select" lazy="true">
<cache usage="read-write"/>
<key>
<column name="ProjectID" sql-type="char(40)"/>
</key>
<index>
<column name="POSITION" not-null="true"/>
</index>
<one-to-many class="Phase"/>
</list>
<list name="Ticklers" cascade="all" fetch="select" lazy="true">
<cache usage="read-write"/>
<key>
<column name="ProjectID" sql-type="char(40)"/>
</key>
<index>
<column name="POSITION" not-null="true"/>
</index>
<one-to-many class="Tickler"/>
</list>
<property name="SourceTemplate" type="string">
<column name="SourceTemplate" not-null="false" unique="false" sql-type="varchar(40)"/>
</property>
<subclass name="Template" discriminator-value="Template" lazy="false">
<subclass name="GlobalTemplate" discriminator-value="GlobalTemplate" lazy="false">
</subclass>
</subclass>
</subclass>
</class>
Full stack trace of any exception that occurs:Code:
09-Oct-07 12:12:06,078 INFO [http-8080-Processor21] ourServer.CommandHandler.runCommand():76 - Commit failed.
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:237)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:143)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at com.ourApplication.server.db.HibernateSessionFactory.rawCommitTransaction(HibernateSessionFactory.java:109)
at com.ourApplication.server.CommandHandler.runCommand(CommandHandler.java:48)
at com.ourApplication.server.CommandServlet.doPost(CommandServlet.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:269)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:174)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:151)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:874)
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)
at java.lang.Thread.run(Thread.java:595)
Caused by: java.sql.BatchUpdateException: Column 'POSITION' cannot be null
at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1257)
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:943)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
... 27 more
(I spaced out the error line a bit above just to highlight it).
Name and version of the database you are using:MySQL 5.0.45 on Windows
The generated SQL (show_sql=true):Code:
09-Oct-07 12:12:04,625 DEBUG [http-8080-Processor21] org.hibernate.SQL.log():401 - insert into TreeNode (DBVERSION, UseDefaultPermissions, OwnerID, Name, Modified, Created, SourceTemplate, CLASS, ID) values (?, ?, ?, ?, ?, ?, ?, 'Project', ?)
09-Oct-07 12:12:04,640 DEBUG [http-8080-Processor21] org.hibernate.SQL.log():401 - insert into Question (DBVERSION, Removeable, Recommended, QuestionText, QuestionType, InternalType, Height, Required, Name, Modified, Created, CLASS, ID) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'StringQuestion', ?)
09-Oct-07 12:12:04,640 DEBUG [http-8080-Processor21] org.hibernate.SQL.log():401 - insert into Question (DBVERSION, Removeable, Recommended, QuestionText, QuestionType, InternalType, Height, Required, Name, Modified, Created, CLASS, ID) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'StringQuestion', ?)
09-Oct-07 12:12:04,640 DEBUG [http-8080-Processor21] org.hibernate.SQL.log():401 - insert into Question (DBVERSION, Removeable, Recommended, QuestionText, QuestionType, InternalType, Height, Required, Name, Modified, Created, CLASS, ID) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'StringQuestion', ?)
09-Oct-07 12:12:04,640 DEBUG [http-8080-Processor21] org.hibernate.SQL.log():401 - insert into Question (DBVERSION, Removeable, Recommended, QuestionText, QuestionType, InternalType, Height, Required, Name, Modified, Created, CLASS, ID) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'StringQuestion', ?)
09-Oct-07 12:12:04,640 DEBUG [http-8080-Processor21] org.hibernate.SQL.log():401 - insert into Question (DBVERSION, Removeable, Recommended, QuestionText, QuestionType, InternalType, Height, Required, Name, Modified, Created, CLASS, ID) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'StringQuestion', ?)
09-Oct-07 12:12:04,640 DEBUG [http-8080-Processor21] org.hibernate.SQL.log():401 - insert into Question (DBVERSION, Removeable, Recommended, QuestionText, QuestionType, InternalType, Height, Required, Name, Modified, Created, CLASS, ID) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'StringQuestion', ?)
09-Oct-07 12:12:04,671 DEBUG [http-8080-Processor21] org.hibernate.SQL.log():401 - update TreeNode set DBVERSION=?, UseDefaultPermissions=?, OwnerID=?, Name=?, Modified=?, Created=? where ID=? and DBVERSION=?
09-Oct-07 12:12:04,671 DEBUG [http-8080-Processor21] [b]org.hibernate.SQL.log():401 - update TreeNode set TreeNodeID=null, POSITION=null where TreeNodeID=?[/b]
As is clear on the last line and from the exception, it's trying to update the Position fild to a NULL value, as well as setting the parent id (TreeNodeID) to null.
The MySQL SQL/DDL field for this entry is
Code:
`POSITION` int(11) NOT NULL default '0',
I know something is not right with this mapping, I can just feel it. The whole map is 2700 lines so I can't include it, but the layout and usage is more or less identical to the above clause.
The weird thing is that this mapping seems to work fine on a few other machines (Linux/Debian and OSX) but on my system (Windows) it fails every time. It's the same code, same database, same Hibernate, etc. So on one machine = everything works, on an other = doesn't work.
I would really appreciate any help, especially with a look at the mapping. I'm slowly getting back into Hibernate after 2 years "off", so it's very uphill running into problems like this one and just trying to get a grip on mapping again.
I did try doing an inverse="true" from reading forums and documents, and although that took away the update error, the new child entered into the database without parent ID and got orphaned instead. I've double and triple checked the creation code for the new child, and I cannot see anything wrong with it (plus it works on other systems, as mentioned before).
Big thanks in advance,
Jack