views:

937

answers:

1

Hi,

I am having an issue with a delete I am trying to do in Hibernate. Everytime I try to delete I get an issue due to child records existing so it cannot delete the parent. I want to delete children and the parent. Here is my parent mapping:

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

Here is the mapping for the child class:

<many-to-one name="communication" column="COM_ID" not-null="true" class="com.fmr.fc.portlet.communications.vo.Communication" cascade="all"/>

EDIT - When I do an insert the data is inserted into the parent and the child.

When I do an update using a new object with the ID of the object I want to modify the parent is updated but any existing children are added a second time. I cannot seem to remove children. When I retrieve an object using the ID and modify this I get an error telling me org.hibernate.LazyInitializationException: could not initialize proxy - the owning Session was closed. I suspect this is because in one getHibernateTemplate() call I am getting the object and I am saving it in another one and these are two different sessions?

When I do a delete I get an error because children exist. I know I am just doing something completley stupid due to lack of having a clue as to how this all works.

Here are my update and delete methods, in this case the update/save is retrieving and modifying before saving. The delete is using a new object with the same ID as the one in the DB I want to delete:

public void deleteCommunication(Communication comm) throws DataAccessException 
{
 getHibernateTemplate().delete(comm);
}

public void saveCommunication(Communication comm) throws DataAccessException
{  
 Communication existing = (Communication)getHibernateTemplate().load(Communication.class, comm.getComId());
 existing.getCommunicationCountries().clear();

 getHibernateTemplate().saveOrUpdate(existing);  
}

UPDATE So here are my new methods but still no joy. I think my issue has to do with the children not being loaded/initialized etc. With the delete though, I cant understand why the cascading delete isn't happening.

thanks so much for your help so far. I have reached my deadline for this work already so if I don't get it fixed over the weekend I am just going to have to resort to executing HQL queries as I know that will work for me :(

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);
    }

    public void updateCommunication(Communication comm) throws DataAccessException
    {  
     HibernateTemplate hibernate = getHibernateTemplate();
     Communication existing = (Communication)hibernate.get(Communication.class, comm.getComId());
     hibernate.initialize( existing.getCommunicationCountries());
     existing.getCommunicationCountries().clear();
     hibernate.saveOrUpdate(existing);  
    }
+1  A: 

In no particular order:

A) Assuming "myID" in your code is your entity's identifier, you should be using session.get() instead of criteria - it's faster and most definitely easier:

MyObject obj = (MyObject) session.get(MyObject.class, new Long(1));

B) If you are using Spring (judging by getHibernateTemplate() call), you should use it consistently :-) and not resort to calling session directly unless absolutely necessary - and it's pretty much never necessary. The above get method would therefore become:

MyObject obj = (MyObject) getHibernateTemplate().get(MyObject.class, new Long(1));

If you need to write a criteria-based query you can use DetachedCriteria and HibernateTemplate.getByCriteria() method:

DetachedCriteria crit = DetachedCriteria.forClass(MyObject.class)
 .add(Property.forName("myId").eq( new Long(1) ) );
List results = getHibernateTemplate().findByCriteria(crit);

C) You normally should not evict() object from session (doing it immediately before closing is rather pointless anyway). Nor should you normally close() the session you've obtained from HibernateTemplate.

D) Finally, as far as automatically saving children (one-to-many collection elements) goes - take a look at this example which provides a good explanation of different cascade settings. Post your mappings / code if you're still having problems.

Update (based on question clarifications):

1) Your mapping looks OK except for cascade on parent in child class (<many-to-one name="communication" cascade="all"/>). You most likely do not want this.

2) LazyInitializationException is thrown because Hibernate by default maps collections as lazy, meaning that children (communicationCountries) will not be loaded until first access. If that access happens when the session is already closed, exception is thrown. You can ensure that collection is populated by calling Hibernate.initialize() on collection.

3) Your delete() should work fine AS LONG AS you're calling it on entity instance returned by Hibernate rather than one you've created yourself (say, unmarshalled from remote call) for which "communicationCountries" collection is not populated. In order for Hibernate to delete children it needs to know they exist.

4) Your update(), on the other hand, is wrong. You're loading an entity, clearing its children, and saving it again - which is fine per se - but that has no connection to the parameter being passed in.

ChssPly76
Thanks for the detailed reply. The example you liked too was actually the one I was using but I suspect I just don't understand what is going on well enough.So if I want to update an object, can I create a new object with the same ID and save it. When I do this the object is updated but if I originally had two children and I add one more I end up with 5, 2 of which are duplicates. Also if I delete all the children from the set none are deleted in the DB.I have the same problem deleting a parent, cascading delete of children is not happening so I get an exception.
Caroline
more detail added in main question....
Caroline
If you want to **update** an object, you most certainly cannot **create** a new object with same ID. Well, you could in theory use `merge()` but I would strongly advice against it until you understand exactly what you're doing.
ChssPly76