I'm attempting to import XML data for objects without ids. I'm hoping that hibernate has the capability to create native keys on the fly for objects represented as dom4j elements.
My existing code works quite well for any data that i comes from my export (i.e. has ids), but it fails when i attempt to "replicate" an element that does not have a non-null id field. As i show in the 1st stack trace.
I've also attempted the code with "save" call instead of "replicate", for which i get a different exception (2nd stack trace).
The "replicate()" code works when i have ids, but clearly is not very close to working when there are no ids.
The "save()" code seems much closer, in that as can be seen in the logs, there seems to be some issue about the child object's reference to it's parent. I'm all for removing it from XML representation... i have embed-xml set to false, so that it is minimized to an id, but... well that still seems to be a problem.
I would prefer not to have to add a "node=xxx" everywhere except the alpha element, and i'm not even sure that would work.
I hope this is possible (and a simple tweak), and any help would be greatly appreciated.
thanks
-w
Data with ids
Code:
<?xml version="1.0" encoding="UTF-8"?>
<objects>
<Alpha>
<id>100</id>
<name>test alpha</name>
<betas>
<Beta>
<id>101</id>
<name>beta one</name>
<alpha>100</alpha>
</Beta>
<Beta>
<id>102</id>
<name>beta two</name>
<alpha>100</alpha>
</Beta>
</betas>
</Alpha>
</objects>
Data without ids Code:
<?xml version="1.0" encoding="UTF-8"?>
<objects>
<Alpha>
<name>test alpha</name>
<betas>
<Beta>
<name>beta one</name>
</Beta>
<Beta>
<name>beta two</name>
</Beta>
</betas>
</Alpha>
</objects>
Hibernate version: 3.2.0
Mapping documents:Alpha.hbm.xmlCode:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="example">
<class name="Alpha" table="Alpha">
<cache usage="nonstrict-read-write" />
<id name="id" type="long" column="Id">
<generator class="native"/>
</id>
<property name="name" type="string" unique="true">
<meta attribute="use-in-tostring">true</meta>
<column name="NAME" not-null="true" unique="true" unique-key="alpha_name_u1" />
</property>
<set name="betas" table="Beta" cascade="all" lazy="false" inverse="true">
<key column="BetaId" />
<one-to-many class="Beta" node="Beta"/>
</set>
</class>
</hibernate-mapping>
Beta.hbm.xmlCode:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="example">
<class name="Beta" table="Beta">
<cache usage="nonstrict-read-write" />
<id name="id" type="long" column="Id">
<generator class="native"/>
</id>
<property name="name" type="string" unique="true">
<meta attribute="use-in-tostring">true</meta>
<column name="NAME" not-null="true" unique="true" unique-key="beta_name_u1" />
</property>
<many-to-one name="alpha" class="Alpha" column="ALPHAID"
not-null="true" embed-xml="false"/>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
String pkg = "example.";
Document document;
Element root;
SAXReader reader = new SAXReader();
document = reader.read( is );
root = document.getRootElement();
Transaction t = domsession.beginTransaction();
for( Object o : root.elements() )
{
Element child = (Element) o;
//domsession.save( pkg + child.getQName().getName(), child );
domsession.replicate( pkg + child.getQName().getName(),
child,
ReplicationMode.OVERWRITE );
}
t.commit();
Full stack trace of any exception that occurs:Stack Trace 1 (replicate)Code:
ERROR 2007-03-15 16:04:51,611 [PoolThread-9] - example.XmlImporter - Exception during import:
org.hibernate.TransientObjectException: instance with null id passed to replicate()
at org.hibernate.event.def.DefaultReplicateEventListener.onReplicate(DefaultReplicateEventListener.java:66)
at org.hibernate.impl.SessionImpl.fireReplicate(SessionImpl.java:932)
at org.hibernate.impl.SessionImpl.replicate(SessionImpl.java:924)
at example.XmlImporter.doImport(XmlImporter.java:91)
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 org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:281)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:187)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:154)
at org.springframework.orm.hibernate3.HibernateInterceptor.invoke(HibernateInterceptor.java:104)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:176)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:210)
at $Proxy24.doImport(Unknown Source)
Stack Trace 2 (save)Code:
ERROR 2007-03-15 16:59:38,267 [PoolThread-7] - example.XmlImporter - Exception during import:
org.hibernate.PropertyValueException: not-null property references a null or transient value: example.Beta.alpha
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:284)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:98)
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.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:437)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:326)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
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 exmaple.XmlImporter.doImport(XmlImporter.java:92)
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 org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:281)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:187)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:154)
at org.springframework.orm.hibernate3.HibernateInterceptor.invoke(HibernateInterceptor.java:104)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:176)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:210)
at $Proxy24.doImport(Unknown Source)
Name and version of the database you are using:
postgresql 8.1.3
The generated SQL (show_sql=true):
SQL 1 (replicate)
NONE. fails before SQL is generated
SQL 2 (save)
Hibernate: select nextval ('public.hibernate_sequence')
Hibernate: select nextval ('public.hibernate_sequence')
Debug level Hibernate log excerpt:
debug 1 (replicate)
DEBUG 2007-03-15 16:56:25,220 [PoolThread-8] - org.hibernate.impl.SessionImpl - opened session at timestamp: 4808716227457024
DEBUG 2007-03-15 16:56:27,086 [PoolThread-8] - org.hibernate.impl.SessionImpl - opened session [dom4j]
WARN 2007-03-15 16:56:29,686 [PoolThread-8] - org.hibernate.impl.SessionImpl - Transaction started on non-root session
DEBUG 2007-03-15 16:56:29,688 [PoolThread-8] - org.hibernate.transaction.JDBCTransaction - begin
DEBUG 2007-03-15 16:56:29,689 [PoolThread-8] - org.hibernate.jdbc.ConnectionManager - opening JDBC connection
DEBUG 2007-03-15 16:56:29,689 [PoolThread-8] - org.hibernate.transaction.JDBCTransaction - current autocommit status: false
debug 2 (save)
DEBUG 2007-03-15 16:59:31,263 [PoolThread-7] - org.hibernate.impl.SessionImpl - opened session at timestamp: 4808716989493248
DEBUG 2007-03-15 16:59:31,756 [PoolThread-7] - org.hibernate.impl.SessionImpl - opened session [dom4j]
WARN 2007-03-15 16:59:33,638 [PoolThread-7] - org.hibernate.impl.SessionImpl - Transaction started on non-root session
DEBUG 2007-03-15 16:59:33,639 [PoolThread-7] - org.hibernate.transaction.JDBCTransaction - begin
DEBUG 2007-03-15 16:59:33,639 [PoolThread-7] - org.hibernate.jdbc.ConnectionManager - opening JDBC connection
DEBUG 2007-03-15 16:59:33,640 [PoolThread-7] - org.hibernate.transaction.JDBCTransaction - current autocommit status: false
DEBUG 2007-03-15 16:59:35,646 [PoolThread-7] - org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG 2007-03-15 16:59:35,647 [PoolThread-7] - org.hibernate.SQL - select nextval ('public.hibernate_sequence')
DEBUG 2007-03-15 16:59:35,651 [PoolThread-7] - org.hibernate.id.SequenceGenerator - Sequence identifier generated: 91012
DEBUG 2007-03-15 16:59:35,652 [PoolThread-7] - org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG 2007-03-15 16:59:35,653 [PoolThread-7] - org.hibernate.event.def.AbstractSaveEventListener - generated identifier: 91012, using strategy: org.hibernate.id.SequenceGenerator
DEBUG 2007-03-15 16:59:35,680 [PoolThread-7] - org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG 2007-03-15 16:59:35,681 [PoolThread-7] - org.hibernate.SQL - select nextval ('public.hibernate_sequence')
DEBUG 2007-03-15 16:59:35,683 [PoolThread-7] - org.hibernate.id.SequenceGenerator - Sequence identifier generated: 91013
DEBUG 2007-03-15 16:59:35,684 [PoolThread-7] - org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG 2007-03-15 16:59:35,684 [PoolThread-7] - org.hibernate.event.def.AbstractSaveEventListener - generated identifier: 91013, using strategy: org.hibernate.id.SequenceGenerator