Java – Hibernate : Foreign key constraint violation problem

hibernatejavamysqlspring

I have a com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException in my code (using Hibernate and Spring) and I can't figure why.
My entities are Corpus and Semspace and there's a many-to-one relation from Semspace to Corpus as defined in my hibernate mapping configuration :

<class name="xxx.entities.Semspace" table="Semspace" lazy="false" batch-size="30">
    <id name="id" column="idSemspace" type="java.lang.Integer" unsaved-value="null">
        <generator class="identity"/>
    </id>
    <property name="name" column="name" type="java.lang.String" not-null="true" unique="true" />
    <many-to-one name="corpus" class="xxx.entities.Corpus" column="idCorpus"
                insert="false" update="false" />
    [...]
</class>
<class name="xxx.entities.Corpus" table="Corpus" lazy="false" batch-size="30">
    <id name="id" column="idCorpus" type="java.lang.Integer" unsaved-value="null">
        <generator class="identity"/>
    </id>
    <property name="name" column="name" type="java.lang.String" not-null="true" unique="true" />
</class>

And the Java code generating the exception is :

Corpus corpus = Spring.getCorpusDAO().getCorpusById(corpusId);
Semspace semspace = new Semspace();
semspace.setCorpus(corpus);
semspace.setName(name);
Spring.getSemspaceDAO().save(semspace);

I checked and the corpus variable is not null (so it is in database as retrieved with the DAO)
The full exception is :

com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`xxx/Semspace`, CONSTRAINT `FK4D6019AB6556109` FOREIGN KEY (`idCorpus`) REFERENCES `Corpus` (`idCorpus`))
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:931)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2941)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1623)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1715)
at com.mysql.jdbc.Connection.execSQL(Connection.java:3249)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1268)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1541)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1455)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1440)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:102)
at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:73)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:33)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2158)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2638)
at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:48)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:298)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:523)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:519)
at org.springframework.orm.hibernate3.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:642)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:373)
at org.springframework.orm.hibernate3.HibernateTemplate.save(HibernateTemplate.java:639)
at xxx.dao.impl.AbstractDAO.save(AbstractDAO.java:26)
at org.apache.jsp.functions.semspaceManagement_jsp._jspService(semspaceManagement_jsp.java:218)
[...]

The foreign key constraint has been created (and added to database) by hibernate and I don't see where the constraint can be violated. The table are innodb and I tried to drop all tables and recreate it the problem remains…

EDIT : Well I think I have a start of answer… I change the log level of hibernate to DEBUG and before it crash I have the following log

insert into Semspace (name, [...]) values (?, [...])

So it looks like it does not try to insert the idCorpus and as it is not null it uses the default value "0" which does not refers to an existing entry in Corpus table…

Best Solution

I get confused w/ the association mappings all the time. Review the association needed and the hibernate mapping config used to create the assiocation.

http://docs.jboss.org/hibernate/core/3.5/reference/en/html/associations.html

is a great recipe book of associations.

Related Question