tags:

views:

973

answers:

2

I'm having a problem implementing a bi-directional parent/child relationship using hibernate 3. The parent, in this case is of the class ReportCriteria. The child is of class PkVisit. I've pasted my hibernate configuration files as well as the underlying java objects below.

ReportCriteria 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>

 <bag name="pkVisits" table="masterPkWeeks" cascade="all-delete-orphan" inverse="true">
        <key column="runId"/>
        <one-to-many class="PkVisit"/>
    </bag>
</class>
</hibernate-mapping>

ReportCriteria bean:

public class ReportCriteriaBean {

private Integer id;

private List<PkVisit> pkVisits =  LazyList.decorate(new ArrayList(), FactoryUtils.instantiateFactory(PkVisit.class));

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

public List<PkVisit> getPkVisits() {
 return pkVisits;
}

public void setPkVisits(List<PkVisit> pkVisits) {
 this.pkVisits = pkVisits;
}

}

PkVisit Configuration:

<hibernate-mapping package="org.fstrf.masterpk.domain">
<class name="PkVisit" table="masterPkWeeks">
 <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="week" column="week" />

</class>
</hibernate-mapping>

PkVisit Bean:

public class PkVisit {
private Integer id;

private ReportCriteriaBean reportCriteriaBean;

private Integer week;

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 Integer getWeek() {
 return week;
}
public void setWeek(Integer week) {
 this.week = week;
}
}

The problem occurs when I try to save an instance of ReportCriteria, which, due to the cascade should also save any child PkVisits as well. However, when the save is called using

hibernateTemplate.saveOrUpdate(reportCriteria);

The following error is generated:

org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value: org.fstrf.masterpk.domain.PkVisit.reportCriteriaBean; nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value: org.fstrf.masterpk.domain.PkVisit.reportCriteriaBean

When I save a report criteria that contains no PkVisits then everything works as I would expect, but as soon as any elements are in the pkVisits list of the ReportCriteria bean the errors occurs.

SOLUTION EDIT:

My problem was that I was never explicitly setting the parent (ReportCriteriaBean) in the children (PkVisits). I remedied the problem by editing my PkVisits setter in the following way:

public void setPkVisits(List<PkVisit> pkVisits) {
 this.pkVisits = pkVisits;
 for(PkVisit visit : pkVisits){
  visit.setReportCriteriaBean(this);
 }
}
A: 

Check if the PkVisit is generated ok, prior to the saveOrUpdate() call.

Then, you may need to eager fetch reportCriteriaBean/pkVisits where you have the hibernate session, prior to accessing them where you don't have hibernate session:

Hibernate.initialize(reportCriteriaBean.getPkVisits());
Mercer Traieste
+1  A: 

It appears that you are not creating the bidirectional link in java properly. I'd recommend creating an add method on ReportCriteriaBean; something to the effect of:

public boolean add(PkVisit pkVisit) {
   boolean added = false;
   added = getPkVisits().add(pkVisit);
   if (added) {
       pkVisit.setReportCriteriaBean(this);
   }
   return added;
}

The error indicates that you cannot save a PkVisit if its ReportCriteriaBean is null. The above code, i think, is your missing link. If you go this route, you just add the PkVisit to the ReportCriteriaBean before persisting the report criteria and all should be well.

Also, here's a link to the hibernate documentation on this subject, section 21.2

zmf
You were correct in saying that the ReportCriteriaBean was null, but because of the way the list of PkVisits was being set this add function by itself did not work. I've edited my original post to indicate the exact change I made. Thanks!
TimmyJ