views:

478

answers:

1

Hi,

I have an issue trying to delete using hibernate. When I try to delete I get an exception saying that children exist and there is a FK violation. I want to delete the children also but the delete doesn't seem to be cascading. After about a week of trying to fix this issue I read that I should be using HibernateInterceptor to keep the session open so that the children can be loaded. When I try to do this now I get the following error:

Failed to load portlet com.blah.blah.CommunicationsPortlet: java.lang.ClassCastException: $Proxy27 incompatible with com.blah.blah.HibernateCommunicationsDAOImpl

Here is the extract from my mapping file:

<set name="communicationCountries" inverse="true" cascade="all,delete-orphan">
<key column="COM_ID" not-null="true" on-delete="cascade" />
<one-to-many class="com.blah.blah.CommunicationCountry"/>
</set>

Here is an extract from the application context:

<bean id="hibernateCommunicationsDAOImplTarget"
class="com.blah.blah.dao.impl.HibernateCommunicationsDAOImpl">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>

<bean id="hibernateCommunicationsDAOImpl" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target"><ref bean="hibernateCommunicationsDAOImplTarget"/></property>
<property name="proxyInterfaces">
<value>com.blah.blah.dao.CommunicationsDAO</value>
</property>
<property name="interceptorNames">
<list>
<value>hibernateInterceptor</value>
</list>
</property>
</bean>

Here is the method in my DAO:

public void deleteCommunication(Integer id) throws DataAccessException
{
HibernateTemplate hibernate = getHibernateTemplate();
Communication existing = (Communication)hibernate.get(Communication.class, id);
hibernate.initialize( existing.getCommunicationCountries());
hibernate.delete(existing);
}

I really don't know what I am doing wrong. I do not have a very complex schema, just one table that results in children (countries). Any ideas what I could do to fix this?

+3  A: 

If you simply want to delete parent along with children, you do NOT need to load the children collection. You don't even need to get() the parent, using load() is enough:

public void deleteCommunication(Integer id) throws DataAccessException {
  HibernateTemplate hibernate = getHibernateTemplate();
  Communication existing = (Communication) hibernate.load(Communication.class, id);
  hibernate.delete(existing);
}

This, of course, assumes the appropriate mapping / cascade in place. Set mapping excerpt you've shown is OK with exception of <key ... on-delete="cascade"/> setting. It's rather tricky for several reasons:

  1. Your database must support it and your schema must define it. You'll get an error if that's not the case.
  2. You will NOT get any performance improvements with this setting if cascade is set to "ALL" because Hibernate would still load each child entity to check for further associations. You need to set cascade to "save-update" in order for this to work, which then has side effects for parent-child relationship with managed lifecycle.

I would therefore suggest to remove on-delete="cascade" for now and to not use it in general until you completely understand all the implications.

HibernateInterceptor you've mentioned has nothing to do with all of this (most certainly not with the delete() method as you have it coded); it's part of open-session-in-view approach to communication with UI layer.

Here's how to troubleshoot all of the above:

  1. Get rid of HibernateInterceptor for now.
  2. Write a unit test to create parent / children in one transaction, commit it, delete them in 2nd transaction, commit it.
  3. If (2) doesn't work, you have a problem with your mapping and / or schema. Post both here and I'll take a look.
  4. If (2) does work and your delete() method above does not work, you have a problem somewhere in your code where delete() is invoked. Perhaps you're loading that same Communication instance and overwriting its communicationCountries collection.
ChssPly76
I'm not sure why but this has worked for me. very strange, this is what I had before except I used .get() instead of .load(). Thanks so much for helping, I can finally relax after a week of wondering why this wasn't working
Caroline
get() vs load() should not matter error-wise. Removing `on-delete=cascade` would :-)
ChssPly76