I'm having a problem where saving a self-referencing association throws an exception when saving the associated object:
Code:
Exception in thread "main" org.hibernate.PropertyValueException: not-null property references a null or transient value
This is a simple example using an Order object and an OrderItem that may contain a List of OrderItem objects itself. The OrderItem does not need a reference to a parent OrderItem, just the List of child OrderItem objects it may contain.
The problem that concerns me is that if I add a third class - say, SubOrderItem - and have OrderItem associated to SubOrderItem instead of OrderItem, everything works fine. The Order, OrderItem, and SubOrderItem are saved:
Code:
Order order= new Order();
order.setName("Order");
OrderItem oi = new OrderItem();
oi.setName("Item A");
order.getOrderItems().add(oi);
SubOrderItem component = new SubOrderItem();
component.setName("Component 1 of Item A");
oi.getComponentOrderItems().add(component);
In other forum postings, the backref error is caused by Hibernate expecting a persistent back reference - in this case, OrderItem to its parent. However, considering the SubOrderItem example works fine, I don't see how the logic for OrderItem would work any differently - it's still an unpersisted instance of an associated Object.
Hibernate version: Hibernate 3.2.0 and 3.2.1
Mapping documents:Order:
Code:
<hibernate-mapping>
<class name="die.hibernate.die.backref.Order" table="Orders">
<id name="id">
<column name="id" />
<generator class="native"/>
</id>
<property name="name"/>
<bag name="orderItems" cascade="all">
<key column="orderId" not-null="true"/>
<one-to-many class="die.hibernate.die.backref.OrderItem"/>
</bag>
</class>
</hibernate-mapping>
OrderItem:
Code:
<hibernate-mapping>
<class name="die.hibernate.die.backref.OrderItem" table="OrderItem">
<id name="id">
<column name="id" />
<generator class="native"/>
</id>
<property name="name"/>
<list name="componentOrderItems" cascade="all">
<key column="parentOrderItemID" not-null="false" />
<list-index column="sequence"/>
<one-to-many class="die.hibernate.die.backref.OrderItem" />
</list>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
Transaction tx = session.beginTransaction();
Order order= new Order();
order.setName("Order");
OrderItem oi = new OrderItem();
oi.setName("Item A");
order.getOrderItems().add(oi);
// this component OrderItem will blow up Hibernate when the Order is saved
OrderItem component = new OrderItem();
component.setName("Component 1 of Item A");
oi.getComponentOrderItems().add(component);
session.saveOrUpdate( order ); // exception thrown here
tx.commit();
Full stack trace of any exception that occurs:Code:
Exception in thread "main" org.hibernate.PropertyValueException: not-null property references a null or transient value: die.hibernate.die.backref.OrderItem._orderItemsBackref
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:108)
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:108)
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:108)
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.impl.SessionImpl.saveOrUpdate(SessionImpl.java:495)
at die.hibernate.die.backref.HibernateSucks.main(HibernateSucks.java:38)
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:90)
Name and version of the database you are using:MySQL 5.0.27-community-nt
The generated SQL (show_sql=true):Code:
Hibernate: insert into Orders (name) values (?)
Hibernate: insert into OrderItem (name, orderId) values (?, ?)
Debug level Hibernate log excerpt:Code:
DEBUG [main] AbstractEntityPersister.logStaticSQL(2688) | Static SQL for entity: die.hibernate.die.backref.OrderItem
DEBUG [main] AbstractEntityPersister.logStaticSQL(2693) | Version select: select id from OrderItem where id =?
DEBUG [main] AbstractEntityPersister.logStaticSQL(2696) | Snapshot select: select orderitem_.id, orderitem_.name as name1_ from OrderItem orderitem_ where orderitem_.id=?
DEBUG [main] AbstractEntityPersister.logStaticSQL(2699) | Insert 0: insert into OrderItem (name, orderId, id) values (?, ?, ?)
DEBUG [main] AbstractEntityPersister.logStaticSQL(2700) | Update 0: update OrderItem set name=? where id=?
DEBUG [main] AbstractEntityPersister.logStaticSQL(2701) | Delete 0: delete from OrderItem where id=?
DEBUG [main] AbstractEntityPersister.logStaticSQL(2705) | Identity insert: insert into OrderItem (name, orderId) values (?, ?)
DEBUG [main] AbstractEntityPersister.logStaticSQL(2688) | Static SQL for entity: die.hibernate.die.backref.SubOrderItem
DEBUG [main] AbstractEntityPersister.logStaticSQL(2693) | Version select: select id from SubOrderItem where id =?
DEBUG [main] AbstractEntityPersister.logStaticSQL(2696) | Snapshot select: select suborderit_.id, suborderit_.name as name2_ from SubOrderItem suborderit_ where suborderit_.id=?
DEBUG [main] AbstractEntityPersister.logStaticSQL(2699) | Insert 0: insert into SubOrderItem (name, id) values (?, ?)
DEBUG [main] AbstractEntityPersister.logStaticSQL(2700) | Update 0: update SubOrderItem set name=? where id=?
DEBUG [main] AbstractEntityPersister.logStaticSQL(2701) | Delete 0: delete from SubOrderItem where id=?
DEBUG [main] AbstractEntityPersister.logStaticSQL(2705) | Identity insert: insert into SubOrderItem (name) values (?)
DEBUG [main] AbstractEntityPersister.logStaticSQL(2688) | Static SQL for entity: die.hibernate.die.backref.Order
DEBUG [main] AbstractEntityPersister.logStaticSQL(2693) | Version select: select id from Orders where id =?
DEBUG [main] AbstractEntityPersister.logStaticSQL(2696) | Snapshot select: select order_.id, order_.name as name0_ from Orders order_ where order_.id=?
DEBUG [main] AbstractEntityPersister.logStaticSQL(2699) | Insert 0: insert into Orders (name, id) values (?, ?)
DEBUG [main] AbstractEntityPersister.logStaticSQL(2700) | Update 0: update Orders set name=? where id=?
DEBUG [main] AbstractEntityPersister.logStaticSQL(2701) | Delete 0: delete from Orders where id=?
DEBUG [main] AbstractEntityPersister.logStaticSQL(2705) | Identity insert: insert into Orders (name) values (?)
DEBUG [main] AbstractCollectionPersister.logStaticSQL(548) | Static SQL for collection: die.hibernate.die.backref.OrderItem.componentOrderItems
DEBUG [main] AbstractCollectionPersister.logStaticSQL(550) | Row insert: update OrderItem set parentOrderItemID=?, sequence=? where id=?
DEBUG [main] AbstractCollectionPersister.logStaticSQL(556) | Row delete: update OrderItem set parentOrderItemID=null, sequence=null where parentOrderItemID=? and id=?
DEBUG [main] AbstractCollectionPersister.logStaticSQL(559) | One-shot delete: update OrderItem set parentOrderItemID=null, sequence=null where parentOrderItemID=?
DEBUG [main] AbstractCollectionPersister.logStaticSQL(548) | Static SQL for collection: die.hibernate.die.backref.Order.orderItems
DEBUG [main] AbstractCollectionPersister.logStaticSQL(550) | Row insert: update OrderItem set orderId=? where id=?
DEBUG [main] AbstractCollectionPersister.logStaticSQL(556) | Row delete: update OrderItem set orderId=null where orderId=? and id=?
DEBUG [main] AbstractCollectionPersister.logStaticSQL(559) | One-shot delete: update OrderItem set orderId=null where orderId=?
DEBUG [main] EntityLoader.<init>(79) | Static select for entity die.hibernate.die.backref.OrderItem: select orderitem0_.id as id1_0_, orderitem0_.name as name1_0_ from OrderItem orderitem0_ where orderitem0_.id=?
DEBUG [main] EntityLoader.<init>(79) | Static select for entity die.hibernate.die.backref.OrderItem: select orderitem0_.id as id1_0_, orderitem0_.name as name1_0_ from OrderItem orderitem0_ where orderitem0_.id=?
DEBUG [main] EntityLoader.<init>(79) | Static select for entity die.hibernate.die.backref.OrderItem: select orderitem0_.id as id1_0_, orderitem0_.name as name1_0_ from OrderItem orderitem0_ where orderitem0_.id=? for update
DEBUG [main] EntityLoader.<init>(79) | Static select for entity die.hibernate.die.backref.OrderItem: select orderitem0_.id as id1_0_, orderitem0_.name as name1_0_ from OrderItem orderitem0_ where orderitem0_.id=? for update
DEBUG [main] EntityLoader.<init>(79) | Static select for entity die.hibernate.die.backref.OrderItem: select orderitem0_.id as id1_0_, orderitem0_.name as name1_0_ from OrderItem orderitem0_ where orderitem0_.id=? for update
INFO [Finalizer] DriverManagerConnectionProvider.close(147) | cleaning up connection pool: jdbc:mysql://localhost:3306/mezzfund?autoReconnect=true
INFO [Finalizer] DriverManagerConnectionProvider.close(147) | cleaning up connection pool: jdbc:mysql://localhost:3306/mezzfund?autoReconnect=true
INFO [Finalizer] DriverManagerConnectionProvider.close(147) | cleaning up connection pool: jdbc:mysql://localhost:3306/mezzfund?autoReconnect=true
DEBUG [main] CascadeEntityLoader.<init>(34) | Static select for action ACTION_MERGE on entity die.hibernate.die.backref.OrderItem: select orderitem0_.id as id1_1_, orderitem0_.name as name1_1_, componento1_.parentOrderItemID as parentOr4_3_, componento1_.id as id3_, componento1_.sequence as sequence3_, componento1_.id as id1_0_, componento1_.name as name1_0_ from OrderItem orderitem0_ left outer join OrderItem componento1_ on orderitem0_.id=componento1_.parentOrderItemID where orderitem0_.id=?
DEBUG [main] CascadeEntityLoader.<init>(34) | Static select for action ACTION_REFRESH on entity die.hibernate.die.backref.OrderItem: select orderitem0_.id as id1_1_, orderitem0_.name as name1_1_, componento1_.parentOrderItemID as parentOr4_3_, componento1_.id as id3_, componento1_.sequence as sequence3_, componento1_.id as id1_0_, componento1_.name as name1_0_ from OrderItem orderitem0_ left outer join OrderItem componento1_ on orderitem0_.id=componento1_.parentOrderItemID where orderitem0_.id=?
DEBUG [main] EntityLoader.<init>(79) | Static select for entity die.hibernate.die.backref.SubOrderItem: select suborderit0_.id as id2_0_, suborderit0_.name as name2_0_ from SubOrderItem suborderit0_ where suborderit0_.id=?
DEBUG [main] EntityLoader.<init>(79) | Static select for entity die.hibernate.die.backref.SubOrderItem: select suborderit0_.id as id2_0_, suborderit0_.name as name2_0_ from SubOrderItem suborderit0_ where suborderit0_.id=?
DEBUG [main] EntityLoader.<init>(79) | Static select for entity die.hibernate.die.backref.SubOrderItem: select suborderit0_.id as id2_0_, suborderit0_.name as name2_0_ from SubOrderItem suborderit0_ where suborderit0_.id=? for update
DEBUG [main] EntityLoader.<init>(79) | Static select for entity die.hibernate.die.backref.SubOrderItem: select suborderit0_.id as id2_0_, suborderit0_.name as name2_0_ from SubOrderItem suborderit0_ where suborderit0_.id=? for update
DEBUG [main] EntityLoader.<init>(79) | Static select for entity die.hibernate.die.backref.SubOrderItem: select suborderit0_.id as id2_0_, suborderit0_.name as name2_0_ from SubOrderItem suborderit0_ where suborderit0_.id=? for update
DEBUG [main] CascadeEntityLoader.<init>(34) | Static select for action ACTION_MERGE on entity die.hibernate.die.backref.SubOrderItem: select suborderit0_.id as id2_0_, suborderit0_.name as name2_0_ from SubOrderItem suborderit0_ where suborderit0_.id=?
DEBUG [main] CascadeEntityLoader.<init>(34) | Static select for action ACTION_REFRESH on entity die.hibernate.die.backref.SubOrderItem: select suborderit0_.id as id2_0_, suborderit0_.name as name2_0_ from SubOrderItem suborderit0_ where suborderit0_.id=?
DEBUG [main] EntityLoader.<init>(79) | Static select for entity die.hibernate.die.backref.Order: select order0_.id as id0_0_, order0_.name as name0_0_ from Orders order0_ where order0_.id=?
DEBUG [main] EntityLoader.<init>(79) | Static select for entity die.hibernate.die.backref.Order: select order0_.id as id0_0_, order0_.name as name0_0_ from Orders order0_ where order0_.id=?
DEBUG [main] EntityLoader.<init>(79) | Static select for entity die.hibernate.die.backref.Order: select order0_.id as id0_0_, order0_.name as name0_0_ from Orders order0_ where order0_.id=? for update
DEBUG [main] EntityLoader.<init>(79) | Static select for entity die.hibernate.die.backref.Order: select order0_.id as id0_0_, order0_.name as name0_0_ from Orders order0_ where order0_.id=? for update
DEBUG [main] EntityLoader.<init>(79) | Static select for entity die.hibernate.die.backref.Order: select order0_.id as id0_0_, order0_.name as name0_0_ from Orders order0_ where order0_.id=? for update
DEBUG [main] CascadeEntityLoader.<init>(34) | Static select for action ACTION_MERGE on entity die.hibernate.die.backref.Order: select order0_.id as id0_1_, order0_.name as name0_1_, orderitems1_.orderId as orderId3_, orderitems1_.id as id3_, orderitems1_.id as id1_0_, orderitems1_.name as name1_0_ from Orders order0_ left outer join OrderItem orderitems1_ on order0_.id=orderitems1_.orderId where order0_.id=?
DEBUG [main] CascadeEntityLoader.<init>(34) | Static select for action ACTION_REFRESH on entity die.hibernate.die.backref.Order: select order0_.id as id0_1_, order0_.name as name0_1_, orderitems1_.orderId as orderId3_, orderitems1_.id as id3_, orderitems1_.id as id1_0_, orderitems1_.name as name1_0_ from Orders order0_ left outer join OrderItem orderitems1_ on order0_.id=orderitems1_.orderId where order0_.id=?
DEBUG [main] OneToManyLoader.<init>(64) | Static select for one-to-many die.hibernate.die.backref.OrderItem.componentOrderItems: select componento0_.parentOrderItemID as parentOr4_1_, componento0_.id as id1_, componento0_.sequence as sequence1_, componento0_.id as id1_0_, componento0_.name as name1_0_ from OrderItem componento0_ where componento0_.parentOrderItemID=?
DEBUG [main] OneToManyLoader.<init>(64) | Static select for one-to-many die.hibernate.die.backref.Order.orderItems: select orderitems0_.orderId as orderId1_, orderitems0_.id as id1_, orderitems0_.id as id1_0_, orderitems0_.name as name1_0_ from OrderItem orderitems0_ where orderitems0_.orderId=?
DEBUG [main] SessionFactoryObjectFactory.<clinit>(39) | initializing class SessionFactoryObjectFactory
DEBUG [main] SessionFactoryObjectFactory.addInstance(76) | registered: 8a8181e50ff34d6d010ff34d6f2d0000 (java:comp/env/hate/SessionFactory)
INFO [main] SessionFactoryObjectFactory.addInstance(86) | Factory name: java:comp/env/hate/SessionFactory
INFO [main] NamingHelper.getInitialContext(26) | JNDI InitialContext properties:{}
WARN [main] SessionFactoryObjectFactory.addInstance(98) | Could not bind factory to JNDI
...
DEBUG [main] SessionFactoryImpl.<init>(308) | instantiated session factory
DEBUG [main] SessionFactoryImpl.checkNamedQueries(390) | Checking 0 named HQL queries
DEBUG [main] SessionFactoryImpl.checkNamedQueries(410) | Checking 0 named SQL queries
DEBUG [main] SessionImpl.<init>(220) | opened session at timestamp: 11680180754
DEBUG [main] JDBCTransaction.begin(54) | begin
DEBUG [main] ConnectionManager.openConnection(415) | opening JDBC connection
DEBUG [main] JDBCTransaction.begin(59) | current autocommit status: false
DEBUG [main] AbstractSaveEventListener.performSaveOrReplicate(289) | executing identity-insert immediately
DEBUG [main] AbstractBatcher.logOpenPreparedStatement(358) | about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG [main] AbstractBatcher.log(393) | insert into Orders (name) values (?)
Hibernate: insert into Orders (name) values (?)
DEBUG [main] IdentifierGeneratorFactory.getGeneratedIdentity(37) | Natively generated identity: 5
DEBUG [main] AbstractBatcher.logClosePreparedStatement(366) | about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG [main] AbstractSaveEventListener.performSaveOrReplicate(289) | executing identity-insert immediately
DEBUG [main] AbstractBatcher.logOpenPreparedStatement(358) | about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG [main] AbstractBatcher.log(393) | insert into OrderItem (name, orderId) values (?, ?)
Hibernate: insert into OrderItem (name, orderId) values (?, ?)
DEBUG [main] IdentifierGeneratorFactory.getGeneratedIdentity(37) | Natively generated identity: 4
DEBUG [main] AbstractBatcher.logClosePreparedStatement(366) | about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
Problems with Session and transaction handling?
Read this:
http://hibernate.org/42.html