I have a Product class which has a 1-to-many association to itself (composite pattern). Below are the pojo, hbm, test code and log/error respectively. Can someone explain what this error is about. Why am I getting this error when setting the parent’s primary key?
Product pojo
public class Product
{
private Long id;
private Set<Product> children = Collections.emptySet();
public void addChild(final Product child)
{
if (children.isEmpty())
{
children = Sets.newHashSet();
}
child.setParent(this);
children.add(child);
}
}
hbm.xml
<class name="Product" table="PRODUCT">
<set name="children" lazy="false" table="PRODUCT">
<key>
<column name="ID" />
</key>
<one-to-many class="Product" />
</set>
</class>
Test
public void save()
{
// Level 1 - mortgage LOB
Product mortgage = new Product();
mortgage.setCode("Mortgage");
Product ml = new Product();
ml.setCode("Mortgage Loan");
Product me = new Product();
me.setCode("Home Equity LOC");
//Level 2
mortgage.addChild(ml);
mortgage.addChild(me);
hibernateTemplate.save(mortgage);
}
log and error
DEBUG [org.hibernate.SQL] insert into PRODUCT (ID, CODE, NAME, STARTDATE, ENDDATE, ISDECISIONABLE, ISSELECTABLE) values (null, ?, ?, ?, ?, ?, ?)
DEBUG [org.hibernate.type.StringType] binding 'Mortgage' to parameter: 1
DEBUG [org.hibernate.type.StringType] binding null to parameter: 2
DEBUG [org.hibernate.type.TimestampType] binding null to parameter: 3
DEBUG [org.hibernate.type.TimestampType] binding null to parameter: 4
DEBUG [org.hibernate.type.BooleanType] binding 'false' to parameter: 5
DEBUG [org.hibernate.type.BooleanType] binding 'false' to parameter: 6
DEBUG [org.hibernate.SQL] call identity()
DEBUG [org.hibernate.SQL] update PRODUCT set ID=? where ID=?
DEBUG [org.hibernate.type.LongType] binding '1' to parameter: 1
ERROR [org.hibernate.event.def.AbstractFlushingEventListener] Could not synchronize database state with session
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.Product
at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:219)
at org.hibernate.type.EntityType.getIdentifier(EntityType.java:397)
at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:78)
A transient object is one that has not been saved. As mapped, your relationship does not use any ‘transitive persistence’, that is to say, you have not told hibernate that when you save the parent you want to save the children. I guess the error is because you have instances of the children (doesn’t matter that the children have the same class of the parent) on the parent (in the session), and hibernate is aware of that, but it doesn’t know what to do with them.
You can either:
1) save the children before saving the parent
2) add the ‘cascade’ attribute to your mapping, something like cascade=”save” or cascade=”all”
see http://docs.jboss.org/hibernate/core/3.3/reference/en/html/objectstate.html#objectstate-transitive