Hibernate version: 3.0.5
We have an object model that has a parent object that has multiple child object sets. Each child object type is modeled as a one-to-many (1-0..*) set with all-delete-orphan cascading. The specific mapping file is shown below. Customer is the parent object and it has Domain, UserGroup, and BranchGroup children.
I'm attempting a delete of Customer and want it to cascade to all children.
UserGroup and BranchGroup also have a many-to-one (0..*-1) association to Domain (also shown below). As such, BranchGroups and UserGroups must be deleted before Domains when a Customer is deleted. If Domain is deleted before BranchGroups a PropertyValueException occurs (shown below) indicating a not-null property violation occured deleting BranchGroup. It appears the order that child types are cascaded (including deletion) from a parent is a function of their ordering in the parent mapping file.
Any suggestion, short of changing the mapping file ordering, how to get around this problem?
Would an event listener (or interceptor) allow me to change the ordering programatically or is there a better way?
Thanks,
Code:
<hibernate-mapping default-cascade="save-update">
<class name="com.bluenotenetworks.common.management.sm.CustomerImpl" dynamic-insert="false" dynamic-update="false" table="CUSTOMER">
<id name="id" type="java.lang.Long" unsaved-value="null">
<column name="ID" sql-type="BIGINT"/>
<generator class="native">
</generator>
</id>
<property name="name" type="java.lang.String">
<column name="NAME" not-null="true" unique="true" sql-type="CHARACTER VARYING(1024)" index="customer_name"/>
</property>
<many-to-one name="network" class="com.bluenotenetworks.common.management.sm.NetworkImpl" fetch="select" cascade="none" foreign-key="CUSTOMER_NETWORK_FKC">
<column name="NETWORK_FK" not-null="true" sql-type="BIGINT"/>
</many-to-one>
<set name="domains" order-by="CUSTOMER_FK" lazy="true" fetch="select" inverse="true" cascade="all-delete-orphan">
<key foreign-key="DOMAIN_CUSTOMER_FKC">
<column name="CUSTOMER_FK" sql-type="BIGINT"/>
</key>
<one-to-many class="com.bluenotenetworks.common.management.sm.DomainImpl"/>
</set>
<set name="branchGroups" order-by="CUSTOMER_FK" lazy="true" fetch="select" inverse="true" cascade="all-delete-orphan">
<key foreign-key="BRANCH_GROUP_CUSTOMER_FKC">
<column name="CUSTOMER_FK" sql-type="BIGINT"/>
</key>
<one-to-many class="com.bluenotenetworks.common.management.sm.BranchGroupImpl"/>
</set>
<set name="userGroups" order-by="CUSTOMER_FK" lazy="true" fetch="select" inverse="true" cascade="all-delete-orphan">
<key foreign-key="USER_GROUP_CUSTOMER_FKC">
<column name="CUSTOMER_FK" sql-type="BIGINT"/>
</key>
<one-to-many class="com.bluenotenetworks.common.management.sm.UserGroupImpl"/>
</set>
</class>
</hibernate-mapping>
Code:
<hibernate-mapping default-cascade="save-update">
<class name="com.bluenotenetworks.common.management.sm.BranchGroupImpl" dynamic-insert="false" dynamic-update="false" table="BRANCH_GROUP">
<id name="id" type="java.lang.Long" unsaved-value="null">
<column name="ID" sql-type="BIGINT"/>
<generator class="native">
</generator>
</id>
<property name="name" type="java.lang.String">
<column name="NAME" not-null="true" unique="false" sql-type="CHARACTER VARYING(1024)" index="branch_group_name"/>
</property>
<many-to-one name="customer" class="com.bluenotenetworks.common.management.sm.CustomerImpl" fetch="select" cascade="none" foreign-key="BRANCH_GROUP_CUSTOMER_FKC">
<column name="CUSTOMER_FK" not-null="true" sql-type="BIGINT"/>
</many-to-one>
<many-to-one name="domain" class="com.bluenotenetworks.common.management.sm.DomainImpl" fetch="select" cascade="none" foreign-key="BRANCH_GROUP_DOMAIN_FKC">
<column name="DOMAIN_FK" not-null="true" sql-type="BIGINT"/>
</many-to-one>
</class>
</hibernate-mapping>
Code:
<hibernate-mapping default-cascade="save-update">
<class name="com.bluenotenetworks.common.management.sm.UserGroupImpl" dynamic-insert="false" dynamic-update="false" table="USER_GROUP">
<id name="id" type="java.lang.Long" unsaved-value="null">
<column name="ID" sql-type="BIGINT"/>
<generator class="native">
</generator>
</id>
<property name="name" type="java.lang.String">
<column name="NAME" not-null="true" unique="false" sql-type="CHARACTER VARYING(1024)" index="user_group_name"/>
</property>
<many-to-one name="customer" class="com.bluenotenetworks.common.management.sm.CustomerImpl" fetch="select" cascade="none" foreign-key="USER_GROUP_CUSTOMER_FKC">
<column name="CUSTOMER_FK" not-null="true" sql-type="BIGINT"/>
</many-to-one>
<many-to-one name="domain" class="com.bluenotenetworks.common.management.sm.DomainImpl" fetch="select" cascade="none" foreign-key="USER_GROUP_DOMAIN_FKC">
<column name="DOMAIN_FK" not-null="true" sql-type="BIGINT"/>
</many-to-one>
</class>
</hibernate-mapping>
Code:
org.springframework.orm.hibernate3.HibernateSystemException: not-null property references a null or transient value: com.bluenotenetworks.common.management.sm.BranchGroupImpl.domain; nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value: com.bluenotenetworks.common.management.sm.BranchGroupImpl.domain
org.hibernate.PropertyValueException: not-null property references a null or transient value: com.bluenotenetworks.common.management.sm.BranchGroupImpl.domain
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
at org.hibernate.event.def.DefaultDeleteEventListener.deleteEntity(DefaultDeleteEventListener.java:205)
at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:109)
at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:587)
at org.hibernate.engine.Cascades$1.cascade(Cascades.java:68)
at org.hibernate.engine.Cascades.cascadeAssociation(Cascades.java:771)
at org.hibernate.engine.Cascades.cascade(Cascades.java:720)
at org.hibernate.engine.Cascades.cascadeCollection(Cascades.java:895)
at org.hibernate.engine.Cascades.cascadeAssociation(Cascades.java:792)
at org.hibernate.engine.Cascades.cascade(Cascades.java:720)
at org.hibernate.engine.Cascades.cascade(Cascades.java:847)
at org.hibernate.engine.Cascades.cascade(Cascades.java:819)
at org.hibernate.event.def.DefaultDeleteEventListener.cascadeBeforeDelete(DefaultDeleteEventListener.java:248)
at org.hibernate.event.def.DefaultDeleteEventListener.deleteEntity(DefaultDeleteEventListener.java:201)
at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:109)
at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:579)
at org.springframework.orm.hibernate3.HibernateTemplate$25.doInHibernate(HibernateTemplate.java:692)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:312)
at org.springframework.orm.hibernate3.HibernateTemplate.delete(HibernateTemplate.java:686)
at org.springframework.orm.hibernate3.HibernateTemplate.delete(HibernateTemplate.java:682)
at com.bluenotenetworks.sm.services.config.ConfigManagerImpl.delete(ConfigManagerImpl.java:229)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:288)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:155)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:122)
at org.springframework.orm.hibernate3.HibernateInterceptor.invoke(HibernateInterceptor.java:163)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:144)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:144)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:174)
at $Proxy1.delete(Unknown Source)
at com.bluenotenetworks.sm.services.test.TestBranchManager.testCreateDeleteBranchGroups(TestBranchManager.java:55)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at com.intellij.rt.execution.junit2.JUnitStarter.main(JUnitStarter.java:31)