There seems to be no automated way to pass a parent’s generated ID value into the children of an object where applicable, even when <generator class="foreign">
is specified in the child.
For example:
Say you have the following relation - A company can have a PIA agreement, but is not required to have one. Your hbm xml configuration would look something like this:
Company.hbm.xml
<hibernate-mapping>
<class name="com.something.something.something.Company" table="COMPANY">
<id name="id" column="ID">
<generator class="increment"/>
</id>
<property name="name" column="NAME"/>
<one-to-one name="pia" class="com.iti.dexcenter.common.object.Pia" cascade="all-delete-orphan" foreign-key="companyId"/>
</class>
</hibernate-mapping>
Pia.hbm.xml
<hibernate-mapping>
<class name="com.iti.dexcenter.common.object.Pia" table="PIA">
<id name="companyId" column="company_id">
<generator class="foreign">
<param name="property">company</param>
</generator>
</id>
<property name="agreementNumber" column="AGREEMENT_NUMBER"/>
<one-to-one name="company" class="com.something.something.something.Company" />
</class>
</hibernate-mapping>
Then, when I call .save(company)
to add the company entry (and the pia entry if one is provided) to the DB, you get this error regardless of whether a pia is set on the company object:
attempted to assign id from null one-to-one property [com.something.something.something.Pia.company]; nested exception is org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [com.something.something.something.Pia.company]
The issue has been reported by many other people without a proper resolution:
Basically, you need to do this bizarre thing here
if(company.getPia() != null) {
company.getPia().setCompany(company);
}
Before you call .save(), as you can see:
@Override
@Transactional
public int insertCompany(Company company) {
int result = -1;
if(company.getPia() != null) {
company.getPia().setCompany(company);
}
try {
template.save(company);
result = company.getId();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
***If you don’t do those 3 lines before calling .save(), you’ll get the error mentioned in the stackoverflow post. Why is this necessary??? ***
Some more code…
Company.java (POJO)
public class Company {
private Integer id;
private String name;
private Pia pia;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setPia(Pia pia) { this.pia = pia; }
public Pia getPia() {
return pia;
}
}
Pia.java (POJO)
public class Pia {
private Integer companyId;
private String agreementNumber;
private Company company;
public Integer getCompanyId() {
return companyId;
}
public void setCompanyId(Integer companyId) {
this.companyId = companyId;
}
public String getAgreementNumber() {
return agreementNumber;
}
public void setAgreementNumber(String agreementNumber) {
this.agreementNumber = agreementNumber;
}
public Company getCompany() {return company;}
public void setCompany(Company company) { this.company = company; }
}