-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: Implementing Cascades with Hibernate Interceptors
PostPosted: Tue Oct 26, 2004 3:19 am 
Newbie

Joined: Thu Jan 22, 2004 5:07 am
Posts: 9
I've implemented cascades for a parent/child relationship in application code using the Lifecycle callbacks. When my application code calls SessionImpl.saveOrUpdate on my parent (Address) object, my code instantiates a new Distance object with a reference to the parent (Address) object and calls saveOrUpdate. No problem.

However, I migrated to the Interceptor framework, and the same relationships / mappings don't work. I get the "not-null property references a null or transient value" exception you see below.

I dug through the source code. And it turns out that SessionImpl first calls the Lifecycle.onSave method of the object being saved (line 811), then adds an Entry object to the session to flag the object with a status of SAVING (line 838), then calls the Interceptor.onSave method (line 855).

Here's the rub: When you save an child object with not-null references to a parent, hibernate calls SessionImpl.isUnsaved on the parent. SessionImpl.isUnsaved returns true if it finds an Entry object with a status of SAVING for the parent.

So if you try to save the child in a Lifecycle callback, no problem. But if you save the child in an Interceptor callback, you get a not-null / transient value constraint error.

This seems like the wrong behavior to me. And the hibernate docs describe the Interceptor framework as a "less-intrusive" alternative to Lifecycle callbacks. So I assume that the Interceptors are supposed to work just like the Lifecycle callbacks.

My questions are:
1) Is this the intended behavior?
2) If not, is it fixed anywhere?
3) What's the recommeded work-around. I've just relaxed the not-null constraint on the parent column and things seem to work fine. But this doesn't seem ideal to me.





Hibernate version:
2.1.1

Mapping documents:
PARENT OBJECT:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="com.jkassis.percolate.contact.address.Address" dynamic-update="false" dynamic-insert="false">
<id name="id" column="id" type="java.lang.Long" unsaved-value="null">
<generator class="increment">
</generator>
</id>
<property name="addressLine" type="string" update="true" insert="true" access="property" column="addressLine" not-null="false" unique="false"/>
<property name="countryRegion" type="java.lang.String" update="true" insert="true" access="property" column="countryRegion" length="100"/>
<property name="crossStreet" type="string" update="true" insert="true" access="property" column="crossStreet" not-null="false" unique="false"/>
<property name="latitude" type="double" update="true" insert="true" access="property" column="latitude" not-null="false" unique="false"/>
<property name="longitude" type="double" update="true" insert="true" access="property" column="longitude" not-null="false" unique="false"/>
<property name="neighborhood" type="string" update="true" insert="true" access="property" column="neighborhood" not-null="false" unique="false"/>
<property name="onlineMapUrl" type="string" update="true" insert="true" access="property" column="onlineMapUrl" not-null="false" unique="false"/>
<property name="postalCode" type="string" update="true" insert="true" access="property" column="postalCode" not-null="false" unique="false"/>
<property name="primaryCity" type="string" update="true" insert="true" access="property" column="primaryCity" not-null="false" unique="false"/>
<property name="secondaryCity" type="string" update="true" insert="true" access="property" column="secondaryCity" not-null="false" unique="false"/>
<property name="subRegion" type="string" update="true" insert="true" access="property" column="subRegion" not-null="false" unique="false"/>
<set name="distances" lazy="false" inverse="true" cascade="none" sort="unsorted">
<key column="addressA">
</key>
<one-to-many class="com.jkassis.percolate.contact.address.distance.Distance"/>
</set>
<!--
To add non XDoclet property mappings, create a file named
hibernate-properties-Address.xml
containing the additional properties and place it in your merge dir.
-->
</class>
</hibernate-mapping>




CHILD OBJECT:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="com.jkassis.percolate.contact.address.distance.Distance" dynamic-update="false" dynamic-insert="false">
<id name="id" column="id" type="java.lang.Long" unsaved-value="null">
<generator class="increment">
</generator>
</id>
<many-to-one name="addressA" class="com.jkassis.percolate.contact.address.Address" cascade="none" outer-join="auto" update="true" insert="true" access="property" column="addressA" not-null="true" unique="false"/>
<many-to-one name="addressB" class="com.jkassis.percolate.contact.address.Address" cascade="none" outer-join="auto" update="true" insert="true" access="property" column="addressB" not-null="true" unique="false"/>
<property name="distance" type="double" update="true" insert="true" access="property" column="distance" not-null="true" unique="false"/>
<property name="units" type="char" update="true" insert="true" access="property" column="units" not-null="true" unique="false"/>
<!--
To add non XDoclet property mappings, create a file named
hibernate-properties-Distance.xml
containing the additional properties and place it in your merge dir.
-->
</class>
</hibernate-mapping>



Code between sessionFactory.openSession() and session.close():
Too much to list.


Full stack trace of any exception that occurs:
[java] net.sf.hibernate.PropertyValueException: not-null property references a null or transient value: com.jkassis.percolate.contact.address.distance.Distance.addressA
[java] 0: net.sf.hibernate.impl.SessionImpl.checkNullability(SessionImpl.java:1211)
[java] 1: net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:873)
[java] 2: net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:817)
[java] 3: net.sf.hibernate.impl.SessionImpl.saveWithGeneratedIdentifier(SessionImpl.java:740)
[java] 4: net.sf.hibernate.impl.SessionImpl.save(SessionImpl.java:717)
[java] 5: net.sf.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:1322)
[java] 6: org.springframework.orm.hibernate.HibernateTemplate$10.doInHibernate(HibernateTemplate.java:259)
[java] 7: org.springframework.orm.hibernate.HibernateTemplate.execute(HibernateTemplate.java:150)
[java] 8: org.springframework.orm.hibernate.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:257)
[java] 9: com.jkassis.gutz.persistence.hibernate.DAOHibImpl.saveOrUpdate(DAOHibImpl.java:246)
[java] 10: com.jkassis.percolate.contact.address.distance.DistanceDAOHibImpl.save(DistanceDAOHibImpl.java:222)
[java] 11: com.jkassis.percolate.contact.address.distance.DistanceDAOHibImpl.access$2(DistanceDAOHibImpl.java:221)
[java] 12: com.jkassis.percolate.contact.address.distance.DistanceDAOHibImpl$AddressDataAccessListener.beforeSave(DistanceDAOHibImpl.java:104)
[java] 13: com.jkassis.gutz.persistence.hibernate.DataAccessInterceptor.fireDataAccessEvent(DataAccessInterceptor.java:231)
[java] 14: com.jkassis.gutz.persistence.hibernate.DataAccessInterceptor.onSave(DataAccessInterceptor.java:178)
[java] 15: net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:855)
[java] 16: net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:817)
[java] 17: net.sf.hibernate.impl.SessionImpl.saveWithGeneratedIdentifier(SessionImpl.java:740)
[java] 18: net.sf.hibernate.impl.SessionImpl.save(SessionImpl.java:717)
[java] 19: net.sf.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:1322)
[java] 20: org.springframework.orm.hibernate.HibernateTemplate$10.doInHibernate(HibernateTemplate.java:259)
[java] 21: org.springframework.orm.hibernate.HibernateTemplate.execute(HibernateTemplate.java:150)
[java] 22: org.springframework.orm.hibernate.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:257)
[java] 23: com.jkassis.gutz.persistence.hibernate.DAOHibImpl.saveOrUpdate(DAOHibImpl.java:246)
[java] 24: com.jkassis.percolate.contact.address.AddressDAOHibImpl.save(AddressDAOHibImpl.java:148)
[java] 25: sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[java] 26: sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[java] 27: sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[java] 28: java.lang.reflect.Method.invoke(Method.java:582)
[java] 29: org.springframework.aop.framework.AopProxyUtils.invokeJoinpointUsingReflection(AopProxyUtils.java:59)
[java] 30: org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:149)
[java] 31: org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:118)
[java] 32: org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:169)
[java] 33: org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:138)
[java] 34: org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:148)
[java] 35: $Proxy0.save(Unknown Source)
[java] 36: sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[java] 37: sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[java] 38: sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[java] 39: java.lang.reflect.Method.invoke(Method.java:582)
[java] 40: com.jkassis.gutz.test.TestObjBaseManager.invoke(TestObjBaseManager.java:275)
[java] 41: org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:138)
[java] 42: org.springframework.aop.framework.Cglib2AopProxy.intercept(Cglib2AopProxy.java:144)
[java] 43: com.jkassis.percolate.contact.address.AddressDAOTestObjBase$$EnhancerByCGLIB$$4429471a.getTestAddressPersistent(<generated>)
[java] 44: com.jkassis.percolate.contact.address.neighborhood.NeighborhoodDAOTestObjBase.getTestNeighborhoodPersistent(NeighborhoodDAOTestObjBase.java:46)
[java] 45: com.jkassis.percolate.contact.address.neighborhood.NeighborhoodDAOTestObjBase$$FastClassByCGLIB$$ac6bd99a.invoke(<generated>)
[java] 46: net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:183)
[java] 47: org.springframework.aop.framework.Cglib2AopProxy$MethodInvocationImpl.invokeJoinpoint(Cglib2AopProxy.java:393)
[java] 48: org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:118)
[java] 49: com.jkassis.gutz.test.TestObjBaseManager.invoke(TestObjBaseManager.java:262)
[java] 50: org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:138)
[java] 51: org.springframework.aop.framework.Cglib2AopProxy.intercept(Cglib2AopProxy.java:144)
[java] 52: com.jkassis.percolate.contact.address.neighborhood.NeighborhoodDAOTestObjBase$$EnhancerByCGLIB$$513f3d70.getTestNeighborhoodPersistent(<generated>)
[java] 53: sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[java] 54: sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[java] 55: sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[java] 56: java.lang.reflect.Method.invoke(Method.java:582)
[java] 57: com.jkassis.gutz.test.TestObjBaseManager.loadAll(TestObjBaseManager.java:343)
[java] 58: com.jkassis.gutz.test.TestObjBaseManager.main(TestObjBaseManager.java:508)
[java] 59: sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[java] 60: sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[java] 61: sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[java] 62: java.lang.reflect.Method.invoke(Method.java:582)
[java] 63: org.apache.tools.ant.taskdefs.ExecuteJava.run(ExecuteJava.java:196)
[java] 64: org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:133)
[java] 65: org.apache.tools.ant.taskdefs.Java.run(Java.java:661)
[java] 66: org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:168)
[java] 67: org.apache.tools.ant.taskdefs.Java.execute(Java.java:77)
[java] 68: org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:269)
[java] 69: org.apache.tools.ant.Task.perform(Task.java:364)
[java] 70: org.apache.tools.ant.Target.execute(Target.java:301)
[java] 71: org.apache.tools.ant.Target.performTasks(Target.java:328)
[java] 72: org.apache.tools.ant.Project.executeTarget(Project.java:1215)
[java] 73: org.apache.tools.ant.Project.executeTargets(Project.java:1063)
[java] 74: org.eclipse.ant.internal.ui.antsupport.InternalAntRunner.run(InternalAntRunner.java:377)
[java] 75: org.eclipse.ant.internal.ui.antsupport.InternalAntRunner.main(InternalAntRunner.java:135)

Name and version of the database you are using:
MySql 4.x

The generated SQL (show_sql=true):
Not required.

Debug level Hibernate log excerpt:
Not required.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 26, 2004 3:22 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
No, don't use Interceptor callbacks to do this kind of thing.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.