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]

Reply via email to