Environment:
Appfuse 2.0 Basic Tapestry
Centos 5
Eclipse 3.2
Hello all,
I have two tables which share a primary key as follows:
patient_basic
-------
pid <PK>
initials
gender
...
patient_phi
----------
pid <PK, FK>
lastname
firstname
midinitial
...
I have managed to get Hibernate to generate the desired schema, but I am
having problems saving the data in my unit tests.
@Entity
@Table(name="patient_basic")
public class Patient extends BaseObject implements Serializable{
...
@Id @GeneratedValue(strategy=GenerationType.AUTO)
public Long getPid() {
return pid;
}
@Transient
public PrivateHealthInfo getPHI() {
return phi;
}
}
-------------------------------------------------------------------------------------------
@Entity
@Table(name="patient_phi")
public class PrivateHealthInfo extends BaseObject implements Serializable{
...
@Id @GeneratedValue(generator="pidPKGenerator")
@GenericGenerator(
name="pidPKGenerator",
strategy="foreign",
parameters={
@Parameter(name="property", value="patient")
}
)
public Long getPid() {
return pid;
}
@OneToOne(optional=false)
@PrimaryKeyJoinColumn
public Patient getPatient() {
return patient;
}
..
}
With this annotation, hibernate generates:
create table patient_basic (pid bigint not null auto_increment, ..., primary
key (pid)) type=InnoDB;
create table patient_phi (pid bigint not null, ..., primary key (pid))
type=InnoDB;
alter table patient_phi add index FK1F59C137131BB8B0 (pid), add constraint
FK1F59C137131BB8B0 foreign key (pid) references patient_basic (pid);
This is exactly what I want, but unfortunately I don't know how to write the
tests. Following the tutorial, I write the PatientForm and PatientFormTest
class as follows:
--------------------------------------------------------------------
public abstract class PatientForm extends BasePage implements
PageBeginRenderListener {
public abstract PatientManager getPatientManager();
public abstract void setPatient(Patient patient);
public abstract Patient getPatient();
public abstract GenericManager<PrivateHealthInfo, Long>
getPrivateHealthInfoManager();
public abstract void setPHI(PrivateHealthInfo phi);
public abstract PrivateHealthInfo getPHI();
public void pageBeginRender(PageEvent event) {
if (getPatient() == null) {
setPatient(new Patient());
}
}
public ILink cancel(IRequestCycle cycle) {
log.debug("Entering 'cancel' method");
return getEngineService().getLink(false, "Home");
}
public ILink save(IRequestCycle cycle) {
Patient patient = null;
PrivateHealthInfo phi = null;
if (getDelegate().getHasErrors()) {
return null;
}
patient = getPatient();
//phi = patient.getPHI();
phi = getPHI();
boolean isNew = (patient.getPid() == null);
patient = getPatientManager().save(patient);
log.debug("Patient id is: " + patient.getPid());
phi.setPid(patient.getPid());
phi = getPrivateHealthInfoManager().save(phi);
String key = (isNew) ? "patient.added" : "patient.updated";
if (isNew) {
PatientList nextPage = (PatientList)
cycle.getPage("PatientList");
nextPage.setMessage(getText(key));
return getEngineService().getLink(false,
nextPage.getPageName());
} else {
setMessage(getText(key));
return null; // return to current page
}
}
}
----------------------------------------------------------------------
public class PatientFormTest extends BasePageTestCase {
private PatientForm page;
protected void onSetUpBeforeTransaction() throws Exception {
super.onSetUpBeforeTransaction();
// these can be mocked if you want a more "pure" unit test
Map<String, Object> map = new HashMap<String, Object>();
map.put("patientManager",
applicationContext.getBean("patientManager"));
map.put("privateHealthInfoManager",
applicationContext.getBean("privateHealthInfoManager"));
page = (PatientForm) getPage(PatientForm.class, map);
}
protected void onTearDownAfterTransaction() throws Exception {
super.onTearDownAfterTransaction();
page = null;
}
public void testAdd() throws Exception {
Patient patient = new Patient();
PrivateHealthInfo phi = new PrivateHealthInfo();
....
//populate beans with data (calling all setters except for pid)
.....
//phi.setPatient(patient);
//patient.setPHI(phi);
page.setPatient(patient);
page.setPHI(phi);
ILink link = page.save(new
MockRequestCycle(this.getClass().getPackage().getName()));
patient = page.getPatient();
phi = patient.getPHI();
log.debug("Testing for null: patient : " + patient);
assertNotNull(patient);
log.debug("Testing for null: patient - intials");
assertNotNull(patient.getInitials());
...
log.debug("Testing for null: phi : " + phi);
assertNotNull(phi);
log.debug("Testing for null: phi - lastname");
assertNotNull(phi.getLastName());
...
assertFalse(page.hasErrors());
assertEquals("PatientList" + EXTENSION, link.getURL());
}
-------------------------------------------------------------------------------------------
testAdd(package_root.webapp.pages.PatientFormTest) Time elapsed: 6.491 sec
<<< ERROR!
org.springframework.orm.hibernate3.HibernateSystemException: attempted to
assign id from null one-to-one property: patient; nested exception is
org.hibernate.id.IdentifierGenerationException: attempted to assign id from
null one-to-one property: patient
Caused by: org.hibernate.id.IdentifierGenerationException: attempted to
assign id from null one-to-one property: patient
at org.hibernate.id.ForeignGenerator.generate(ForeignGenerator.java:44)
at
org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:98)
at
org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:186)
at
org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:240)
at
org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:120)
at
org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:53)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:677)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:661)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:665)
at
org.springframework.orm.hibernate3.HibernateTemplate$23.doInHibernate(HibernateTemplate.java:765)
at
org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:372)
at
org.springframework.orm.hibernate3.HibernateTemplate.merge(HibernateTemplate.java:762)
at
org.appfuse.dao.hibernate.GenericDaoHibernate.save(GenericDaoHibernate.java:64)
at
org.appfuse.service.impl.GenericManagerImpl.save(GenericManagerImpl.java:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at
org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:304)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:172)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:139)
at
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:107)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
at
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy32.save(Unknown Source)
at package_root.webapp.pages.PatientForm.save(PatientForm.java:61)
at
package_root.webapp.pages.PatientFormTest.testAdd(PatientFormTest.java:58)
I have tried several variations within the PatientFormTest class but I
receive either the exception above, a "ids for this class must be manually
assigned" exception, or a "object references an unsaved transient instance"
exception.
The patient_phi table's pid is a foreign primary key referencing
patient_basic table's pid.
For a new patient, the pid is not known until the save method is called.
Ideally, I would like Hibernate to generate a pid for the new patient in
patient_basic and then populate the same pid to patient_phi.
How could I obtain this functionality? Currently, both beans have their own
Managers. Should I just use one Manager?
I've been struggling to get this to work for a few days now. Sorry for my
lack of understanding. I have read a few documentation which only show how
to write the Hibernate annotations; nothing on how to save/use the data
afterwards.
Thanks in advanced.
--
View this message in context:
http://www.nabble.com/Saving-Beans-with-One-to-One-Shared-Primary-Keys-tf3962234s2369.html#a11244604
Sent from the AppFuse - User mailing list archive at Nabble.com.
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]