views:

221

answers:

1

I have a parent child relationship in which the parent has a collection of children (a set to be specific). The child collection is setup with cascade="all-delete-orphan". When I initially save the parent element everything works as expected. However, when I update the parent and save again, all the children are re-saved.

This behavior leads me to believe that the parent is losing its reference to the collection of children, and therefore when persisting all the children are re-saved. It seems the only way to fix this is to not use the setter method of this child collection, but unfortunately this setter is called implicitly in my application (Spring MVC is used to bind a multi-select form element to this collection, and the setter is called by spring on the form submission). Overwriting this setter to not lose the reference (ie, do a colleciton.clear() and collection.addAll(newCollection) rather than collection = newCollection) is apparently a hibernate no-no, as is pointed out here: https://forum.hibernate.org/viewtopic.php?t=956859

Does anyone know how to circumvent this problem? I've posted some of my code below.

The parent hibernate configuration:

<hibernate-mapping package="org.fstrf.masterpk.domain">
<class name="ReportCriteriaBean" table="masterPkReportCriteria">

    <id name="id" column="id">
        <generator class="org.hibernate.id.IncrementGenerator" />
    </id>

    <set name="treatmentArms" table="masterPkTreatmentArms" 
         sort="org.fstrf.masterpk.domain.RxCodeComparator" lazy="false" cascade="all-delete-orphan" inverse="true">
        <key column="runid"/>
        <one-to-many class="TreatmentArm"/>
    </set>
</class>
</hibernate-mapping>

The parent object:

public class ReportCriteriaBean{

    private Integer id;
    private Set<TreatmentArm> treatmentArms;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }

    public Set<TreatmentArm> getTreatmentArms() {
        return treatmentArms;
    }
    public void setTreatmentArms(Set<TreatmentArm> treatmentArms) {
        this.treatmentArms = treatmentArms;
        if(this.treatmentArms != null){
        for(TreatmentArm treatmentArm : this.treatmentArms){
            treatmentArm.setReportCriteriaBean(this);
        }
    }
}

The child hibernate configuration:

<hibernate-mapping package="org.fstrf.masterpk.domain">
    <class name="TreatmentArm" table="masterPkTreatmentArms">
        <id name="id" column="id">
            <generator class="org.hibernate.id.IncrementGenerator" />
        </id>

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

        <property name="rxCode" column="rxCode" not-null="true"/>
    </class>
</hibernate-mapping>

The child object:

public class TreatmentArm {

    private Integer id;
    private ReportCriteriaBean reportCriteriaBean;
    private String rxCode;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public ReportCriteriaBean getReportCriteriaBean() {
        return reportCriteriaBean;
    }
    public void setReportCriteriaBean(ReportCriteriaBean reportCriteriaBean) {
        this.reportCriteriaBean = reportCriteriaBean;
    }
    public String getRxCode() {
        return rxCode;
    }
    public void setRxCode(String rxCode) {
        this.rxCode = rxCode;
    }
}
A: 

It may come from this Hibernate Bug.

Javi
In my scenario adding a child only performs a single insert, but the problem is that due to the setTreatmentArms() call from Spring, hibernate loses it's reference to the set of children and therefore when persisted it simple re-inserts them all.For instance, a new parent is created with a set of children (CH1, CH2). When saved everything works. However, if I then modify this collection by removing CH2 (via a multi-select form object bound to my child collection) and persist again, the new child set is now (CH1, CH2, CH1) where it should be just (CH1).
TimmyJ