For the past week or so I have been using Hibernate 3.0 and MySQL 4.0.18 to persist a graph of objects. The graph is sumarized as follows:
Quote:
The graph is composed of mainly three objects: Parent, Node and Link. Parent contains a Set of Nodes and a Set of Links. A Link contains a reference to a source Node and another one to a target Node. The Node has a Set of incomming Links and another one of outgoing Links. Both Node and Link have a reference back to Parent.
Code goes along these lines:
Quote:
Parent p = new Parent();
Node src = new Node();
src.setParent(p);
p.getNodes().add(src);
Node tgt = new Node();
tgt.setParent(p);
p.getNodes().add(tgt);
Link lnk = new Link();
p.getLinks().add(lnk);
lnk.setSourceNode(src);
lnk.setTargetNode(tgt);
src.getOutgoings().add(lnk);
tgt.getIncomings().add(lnk);
session.save(p);
Here is a section of the Parent.hbm.xml file:
Quote:
<set name="links" inverse="true" cascade="all-delete-orphan">
<key column="parent"/>
<one-to-many class="Link"/>
</set>
<set name="nodes" inverse="true" cascade="all-delete-orphan">
<key column="parent"/>
<one-to-many class="Node"/>
</set>
Here is a section of the Node.hbm.xml file:
Quote:
<many-to-one name="parent" not-null="true"/>
<many-to-one name="sourceNode" not-null="true"/>
<many-to-one name="targetNode" not-null="true"/>
Here is a section of the Link.hbm.xml file:
Quote:
<many-to-one name="parent" not-null="true"/>
<set name="incoming" inverse="true" cascade="all-delete-orphan">
<key column="sourceNode"/>
<one-to-many class="Link"/>
</set>
<set name="outgoing" inverse="true" cascade="all-delete-orphan">
<key column="targetNode"/>
<one-to-many class="Link"/>
</set>
When I try to persist this graph using session.save(aParent) I get the following exception:
Quote:
org.hibernate.PropertyValueException: not-null property references a null or transient value:
Link.targetNode
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:234)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:158)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:184)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:173)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:96)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:69)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:416)
at org.hibernate.engine.Cascades$5.cascade(Cascades.java:153)
at org.hibernate.engine.Cascades.cascade(Cascades.java:721)
at org.hibernate.engine.Cascades.cascadeCollection(Cascades.java:860)
at org.hibernate.engine.Cascades.cascade(Cascades.java:739)
at org.hibernate.engine.Cascades.cascade(Cascades.java:817)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:361)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:263)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:158)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:184)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:173)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:96)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:69)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:416)
at org.hibernate.engine.Cascades$5.cascade(Cascades.java:153)
at org.hibernate.engine.Cascades.cascade(Cascades.java:721)
at org.hibernate.engine.Cascades.cascadeCollection(Cascades.java:860)
at org.hibernate.engine.Cascades.cascade(Cascades.java:739)
at org.hibernate.engine.Cascades.cascade(Cascades.java:817)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:361)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:263)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:158)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:184)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:173)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:69)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:429)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:424)
at Main.createGraph(Main.java:452)
at Main.main(Main.java:383)
After some Hibernate debugging it seems that when Hibernate tries to save the only Link object I have in my test graph it nullifies either the source or target Node (it seems to vary for each debugging session). Since both Link.sourceNode and Link.targetNode cannot be null, the exception is thown.
Some questions:
(1) Since I would expect an ORM implementation to take care of graphs, what am I doing wrong here?
(2) Shouldnt Hibernate first reach all dependent object and then start saving them?
(3) If this is a bug, is there a work around?
Any help would be greatly appreciated!
thanks,
-- yuri
Read the rules before posting!
http://www.hibernate.org/ForumMailingli ... AskForHelp
Hibernate version:
Mapping documents:
Code between sessionFactory.openSession() and session.close():
Full stack trace of any exception that occurs:
Name and version of the database you are using:
The generated SQL (show_sql=true):
Debug level Hibernate log excerpt: