tags:

views:

374

answers:

1

Here is my situation: I load an object that contains a bi-directional parent child relationship into my database. Later, that object is loaded into my UI where changes can be made, including deleting any number of children from the child set. This modified copy of my object is then loaded using the saveOrUpdate method. However, when this modified copy is saved any deleted children remain in the database (new children being added to the set works fine). There are no errors being thrown throughout this process but I need these removed children to actually be removed from the database. I've pasted the relevant portions of my hibernate and java code below.

Parent hibernate config:

<bag name="specimenTypes" table="masterPkSpecimenType" cascade="all-delete-orphan" inverse="true">
    <key column="runid"/>
    <one-to-many class="SpecimenType"/>
</bag>

Child hibernate config:

<many-to-one name="reportCriteriaBean" class="ReportCriteriaBean" column="runid" not-null="true" />

Parent object code:

public List<SpecimenType> getSpecimenTypes() {
 return specimenTypes;
}

public void setSpecimenTypes(List<SpecimenType> specimenTypes) {
 this.specimenTypes = specimenTypes;
 if(this.specimenTypes != null){
  for(SpecimenType specType : this.specimenTypes){
   specType.setReportCriteriaBean(this);
  }
 }
}

Child object code:

public ReportCriteriaBean getReportCriteriaBean() {
 return reportCriteriaBean;
}
public void setReportCriteriaBean(ReportCriteriaBean reportCriteriaBean) {
 this.reportCriteriaBean = reportCriteriaBean;
}

EDIT:

Apparently my problem is due to explicitly calling setSpecimenTypes() after I retrieve the parent object from the DB, and before I save the updated object back. the reason I am doing this is because, due to some dynamic List binding, I need the List to be a specific implementation of List (specifically apache's LazyList) when it is presented to the UI. However, when the object gets pulled from the DB it is not implemented in this way so I create a LazyList copy of the regular List that was pulled from the database and call setSpecimenTypes() to replace it with my newly populated LazyList. Does anyone know of a way for me to do this?

A: 

Your mapping looks correct. How are you removing the children? Something akin to getSpecimenTypes().remove(X) or do you have a special method for that (if so, can you post it)?

Also, when your parent object is transferred to UI layer and back - is it done within the same session? Are you sure noone is resetting children collection by calling setSpecimenTypes() somewhere in the middle?

Update (based on clarification):

Resetting specimenTypes is definitely a problem. How would Hibernate know that you've removed a particular element? Deletes are tracked within Hibernate's own PersistentList which wraps your list when your parent object is loaded.

LazyList (I'm assuming you mean the one from Commons Collections) is a decorator, so you can create another getter method within your parent object that would wrap your specimenTypes collection into LazyList and return that (caching it in a member variable for efficiency during repeated access attempts).

The bottom line here is you should never overwrite collection managed by Hibernate with your own version.

ChssPly76
I am calling setSpecimenTypes() before I update the object (for reasons I've outlined in an update to my post), I don't understand why this matters though. Shouldn't the child list be updated to reflect whatever the current child set contains, thereby removing any old children DB entries?
TimmyJ
Thanks for the help. I am still having a problem though. When I changed the getter to return the decorated List I get the following error when the parent class is being pulled from the DB: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance.I am sure that the setSpecimenTypes is never called (I went so far as to make it private) . You mention above that I should create *another* getter, not replace the current one as I did. Is there a reason my way would be incorrect?
TimmyJ
The problem with returning decorated list from existing getter is that its no longer Hibernate's PersistentList. Hibernate doesn't know you've wrapped it (or how to unwrap it) - it just sees that the PersistentList that was there is now gone - hence the exception. You really do need another getter - but if your code depends on `getSpecimenTypes()` you can make a private `getSpecimentTypesDB()` and map that in Hibernate. I personally prefer to decorate UI beans rather then business objects, but either approach has its place.
ChssPly76
This worked great, thanks again for all the help
TimmyJ