Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelp
Basically, I'm trying to use the dom4j session to create a data transfer between databases. So, I have an extractor that creates an XML document from a database, and then a have a populator that takes the XML document and replicates() objects in an empty DB.
This works great, except for when I try to populate a pair of classes that have a bidirectional relationship (one-to-many and many-to-one). I get a "java.sql.SQLException: Cannot add or update a child row: a foreign key constraint fails" error message.
Am I going about this the wrong way? Should I be using something besides replicate()?
Hibernate version:
3.0.5
Mapping documents:
Code:
<hibernate-mapping
package="data">
<class name="Foo"
table="foo"
>
<id name="id"
node="@id"
type="string"
unsaved-value="null"
column="foo_id" >
<generator class="uuid" />
</id>
<property
name="prop1"
column="prop1"
type="string"
/>
<many-to-one
name="bar"
column="bar_id"
class="Bar"
not-null="false"
embed-xml="false"
/>
<property
name="index"
column="foo_index"
type="int"
update="true"
/>
</class>
<class name="Bar"
table="bar"
>
<id name="id"
node="@id"
type="string"
unsaved-value="null"
column="bar_id" >
<generator class="uuid" />
</id>
<list
name="foos"
node="foos"
embed-xml="true"
inverse="true"
lazy="false">
<key column="bar_id"/>
<list-index column="foo_index"/>
<one-to-many
class="Foo"
embed-xml="false"
node="foo"
/>
</list>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Here is the populator:
Code:
try
{
SAXReader reader = new SAXReader();
Document doc = reader.read(new File("content.xml"));
Session session = currentSession();
Session s = session.getSession(EntityMode.DOM4J);
Transaction txn = s.beginTransaction();
{
List elems = doc.getRootElement().elements();
Iterator it = elems.iterator();
while(it.hasNext())
{
Element e = (Element)it.next();
log.debug(e.getName());
if(e.getName().equals("Foo"))
s.replicate("data.Foo",e, ReplicationMode.IGNORE);
if(e.getName().equals("Bar"))
s.replicate("data.Bar",e, ReplicationMode.IGNORE);
}
}
txn.commit();
}
catch(DocumentException e)
{
log.error(e);
}
Full stack trace of any exception that occurs:150 [main] ERROR org.hibernate.util.JDBCExceptionReporter - Cannot add or update a child row: a foreign key constraint fails
291 [main] ERROR org.hibernate.event.def.AbstractFlushingEventListener - Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: could not insert: [data.Foo]
at org.hibernate.exception.ErrorCodeConverter.convert(ErrorCodeConverter.java:74)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.entity.BasicEntityPersister.insert(BasicEntityPersister.java:1869)
at org.hibernate.persister.entity.BasicEntityPersister.insert(BasicEntityPersister.java:2200)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:46)
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:136)
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:329)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:86)
at Test.reconstitute(Test.java:69)
at Test.main(Test.java:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:78)
Caused by: java.sql.SQLException: Cannot add or update a child row: a foreign key constraint fails
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2851)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1531)
at com.mysql.jdbc.ServerPreparedStatement.serverExecute(ServerPreparedStatement.java:1366)
at com.mysql.jdbc.ServerPreparedStatement.executeInternal(ServerPreparedStatement.java:952)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1974)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1897)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1758)
at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:22)
at org.hibernate.persister.entity.BasicEntityPersister.insert(BasicEntityPersister.java:1853)
... 17 more
Exception in thread "main" org.hibernate.exception.ConstraintViolationException: could not insert: [data.Foo]
at org.hibernate.exception.ErrorCodeConverter.convert(ErrorCodeConverter.java:74)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.entity.BasicEntityPersister.insert(BasicEntityPersister.java:1869)
at org.hibernate.persister.entity.BasicEntityPersister.insert(BasicEntityPersister.java:2200)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:46)
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:136)
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:329)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:86)
at Test.reconstitute(Test.java:69)
at Test.main(Test.java:40)
Name and version of the database you are using:MySQL 4.1.12
The generated SQL (show_sql=true):0 [main] DEBUG Test - Creating new Hibernate Session: main
10 [main] DEBUG Test - Foo
Hibernate: select foo_id from foo where foo_id =?
70 [main] DEBUG Test - Foo
Hibernate: select foo_id from foo where foo_id =?
70 [main] DEBUG Test - Bar
Hibernate: select bar_id from bar where bar_id =?
Hibernate: insert into foo (prop1, bar_id, foo_index, foo_id) values (?, ?, ?, ?)
-----------
The content.xml document looks like this:
Code:
<root>
<Foo id="402881e4045ce90c01045ce90f950002">
<prop1>abcd</prop1>
<bar>402881e4045ce90c01045ce90f770001</bar>
<index>0</index>
</Foo>
<Foo id="402881e4045ce90c01045ce90f9f0003">
<prop1>456</prop1>
<bar>402881e4045ce90c01045ce90f770001</bar>
<index>1</index>
</Foo>
<Bar id="402881e4045ce90c01045ce90f770001">
<foos>
<foo>402881e4045ce90c01045ce90f950002</foo>
<foo>402881e4045ce90c01045ce90f9f0003</foo>
</foos>
</Bar>
</root>
It was created using this:
Code:
private static void createDocument() {
Session sess;
sess = currentSession();
Session s = sess.getSession(EntityMode.DOM4J);
Document doc = DocumentHelper.createDocument();
Element root = doc.addElement("root");
List results = s.createQuery("from Foo foo ").list();
addResultsToNode(results, root);
results = s.createQuery("from Bar bar ").list();
addResultsToNode(results, root);
OutputFormat format = OutputFormat.createPrettyPrint();
try
{
XMLWriter writer = new XMLWriter(new FileWriter("content.xml"), format);
writer.write(doc);
writer.close();
} catch(IOException ioe) { }
}
private static void addResultsToNode(List results, Element root)
{
for (Iterator i = results.iterator(); i.hasNext();) {
Element e = (Element) i.next();
if(e != null)
{
log.debug("e: "+e.toString());
root.add(e);
}
}
}