I'm trying to import some parent/child related data from an XML file into an Oracle 8i database by use of the 'experimental XML Mapping' feature.
No matter what I'm trying, I do not manage to make the import working (exporting is no problem and works fine). I've been looking around on the net for comparable examples and have read the Hibernate documentation, but haven't found any helpful resource or solution for my problem.
For asking here in the forum, I've prepared an example implementation, which should be easy to understand. The problem I've encountered is, that both the Parent and Child objects have a surrogate identifier generated by a sequence. When saving the Parent to the dom4jSession, a new identifier will be correctly generated for the transient Parent object. Due to cascade="true" also a new identifier will be correctly generated for the related transient Child object. But the Child object will not be automatically related to its Parent object and the foreign key field (Parent parent) of the Child will still be null and causes an exception.
Because of the parent/child mapping and the enabled cascading I had expected, that Hibernate automatically would save the Child to the database and would use the generated identifier of the Parent for the foreign key column (parentid) of the Child. Is this expectation wrong or am I doing something wrong? How can I manage to import parent/child related data from an XML file? I'll be deeply grateful for any help.
Hibernate version: 3.0.3
The DDL statements for the database tables/sequences:
Code:
CREATE SEQUENCE seq_parent
INCREMENT BY 1
START WITH 1
NOCYCLE
;
CREATE SEQUENCE seq_child
INCREMENT BY 1
START WITH 1
NOCYCLE
;
CREATE TABLE parent (
pid NUMBER(19) NOT NULL,
parentname VARCHAR2(20) NOT NULL,
CONSTRAINT idx_pk_parent
PRIMARY KEY (pid)
)
;
CREATE TABLE child (
cid NUMBER(19) NOT NULL,
parentid NUMBER(19) NOT NULL,
childname VARCHAR2(20) NOT NULL,
CONSTRAINT idx_pk_child
PRIMARY KEY (cid),
CONSTRAINT cs_parent_child
FOREIGN KEY (parentid)
REFERENCES parent
ON DELETE CASCADE
)
;
The content of the xml file which to import:Code:
<?xml version="1.0" encoding="UTF-8"?>
<exchange>
<parent>
<pid></pid>
<parentname>father</parentname>
<children>
<child>
<cid></cid>
<childname>son</childname>
<parent></parent>
</child>
</children>
</parent>
</exchange>
Mapping documents:Code:
<?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="parentchild.model">
<class name="Parent" table="PARENT" node="parent">
<id name="pid"
column="PID"
type="long"
>
<generator class="native">
<param name="sequence">seq_parent</param>
</generator>
</id>
<property name="parentname"
column="PARENTNAME"
type="string"
not-null="true"
length="20"
/>
<!-- bi-directional one-to-many association to Child -->
<set name="children"
lazy="true"
inverse="true"
cascade="all"
embed-xml="true"
>
<key column="PARENTID"/>
<one-to-many class="Child"/>
</set>
</class>
<class name="Child" table="CHILD" node="child">
<id name="cid"
column="CID"
type="long"
>
<generator class="native">
<param name="sequence">seq_child</param>
</generator>
</id>
<property name="childname"
type="string"
column="CHILDNAME"
not-null="true"
length="20"
/>
<!-- bi-directional many-to-one association to Parent -->
<many-to-one name="parent"
column="PARENTID"
class="Parent"
not-null="true"
embed-xml="false"
/>
</class>
</hibernate-mapping>
Code for importing:Code:
Session session = HibernateUtil.getSession();
Session dom4jSession = session.getSession(EntityMode.DOM4J);
HibernateUtil.beginTransaction();
String filename = "parentchild.xml";
File file = new File(filename);
SAXReader reader = new SAXReader();
Document doc = reader.read(file);
List data = doc.selectNodes("/exchange/parent");
Iterator it = data.iterator();
while (it.hasNext()) {
dom4jSession.save("parentchild.model.Parent", it.next());
}
HibernateUtil.commitTransaction();
HibernateUtil.closeSession();
Debug level Hibernate log excerpt:Code:
DEBUG AbstractSaveEventListener:409 - transient instance of: parentchild.model.Parent
DEBUG DefaultSaveOrUpdateEventListener:159 - saving transient instance
DEBUG AbstractBatcher:277 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG SQL:311 - select hibernate.seq_parent.nextval from dual
Hibernate: select hibernate.seq_parent.nextval from dual
DEBUG AbstractBatcher:365 - preparing statement
DEBUG SequenceGenerator:87 - Sequence identifier generated: 12
DEBUG AbstractBatcher:285 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG AbstractBatcher:403 - closing statement
DEBUG AbstractSaveEventListener:89 - generated identifier: 12, using strategy: org.hibernate.id.SequenceGenerator
DEBUG AbstractSaveEventListener:132 - saving [parentchild.model.Parent#12]
DEBUG Cascades:836 - processing cascade ACTION_SAVE_UPDATE for: parentchild.model.Parent
DEBUG Cascades:861 - done processing cascade ACTION_SAVE_UPDATE for: parentchild.model.Parent
DEBUG Cascades:836 - processing cascade ACTION_SAVE_UPDATE for: parentchild.model.Parent
DEBUG Cascades:890 - cascade ACTION_SAVE_UPDATE for collection: parentchild.model.Parent.children
DEBUG Cascades:153 - cascading to saveOrUpdate: parentchild.model.Child
DEBUG AbstractSaveEventListener:409 - transient instance of: parentchild.model.Child
DEBUG DefaultSaveOrUpdateEventListener:159 - saving transient instance
DEBUG AbstractBatcher:277 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG SQL:311 - select hibernate.seq_child.nextval from dual
Hibernate: select hibernate.seq_child.nextval from dual
DEBUG AbstractBatcher:365 - preparing statement
DEBUG SequenceGenerator:87 - Sequence identifier generated: 12
DEBUG AbstractBatcher:285 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG AbstractBatcher:403 - closing statement
DEBUG AbstractSaveEventListener:89 - generated identifier: 12, using strategy: org.hibernate.id.SequenceGenerator
DEBUG AbstractSaveEventListener:132 - saving [parentchild.model.Child#12]
org.hibernate.PropertyValueException: not-null property references a null or transient value: parentchild.model.Child.parent
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
at ...