Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[eclipselink-users] i encountere a Null primary key in some unit of work clone

Hi all

i'm using eclipselink 1.0.2 and i have some problem using custom insert mechanism. Here is my model

@MappedSuperclass
public abstract class DomainObject implements Serializable {

    /**
     *
     */
    private static final long serialVersionUID = 8169331770517578695L;

    public static final String PROP_ID = "id";

    @Id
    @ReturnInsert
    protected Integer id;

  

    public Integer getId() {
        return id;
    }

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

    @Override
    public int hashCode() {
              ... generated from eclipse....
    }

    @Override
    public boolean equals(Object obj) {
       ... generated from eclipse....
    }
}

@Entity
@Table(name = "TOPCARE.PAT_VIEW")
@AttributeOverrides(value = { @AttributeOverride(name = "id", column = @Column(name = "PATIENT_ID")) })
public class Patient extends DomainObject {

@OneToMany(mappedBy = "patient", cascade = { MERGE, REFRESH }, fetch = LAZY)
    @OrderBy("measurementDate DESC")
    private List<Measurement> measurements = new Vector<Measurement>();
  
    ...

    public void addMeasurement(Measurement measurement) {
        if (measurement != null && !measurements.contains(measurement)) {
            measurements.add(0, measurement);
            measurement.setPatient(this);
        }
    }
   .....
}


@MappedSuperclass
public abstract class AbstractMeasurement extends DomainObject {
      ...

    @ManyToOne(cascade = { MERGE, REFRESH })
    @JoinColumn(name = "PAT_PATIENT_ID", referencedColumnName = "PATIENT_ID")
    private Patient patient;

    @OneToOne(cascade = { PERSIST, MERGE, REFRESH })
    @JoinColumn(name = "WORK_FLOW_ID", referencedColumnName = "WORKFLOW_ID")
    protected Workflow workflow;

    public AbstractMeasurement() {
        init();
    }

    public AbstractMeasurement(Patient patient, Workflow workflow) {
        setPatient(patient);
        if (workflow == null)
            workflow = new Workflow(patient);
        this.workflow = workflow;
        init();
    }

    private void init() {
        // values = new HashMap<Object, AbstractMeasurementValue>();
        if (patient == null)
            patient = new Patient();
        if (workflow == null)
            workflow = new Workflow();
        if (measurementDate == null)
            measurementDate = new Date();
    }
     ....

    public Patient getPatient() {
        return patient;
    }

    public void setPatient(Patient patient) {
        if (patient != null && !patient.equals(this.patient)) {
            this.patient = patient;
            this.patient.addMeasurement(this);
        }
    }

@Entity
@Table(name = "TOPCARE.MEASUREMENT_VIEW")
@AttributeOverrides( {
        @AttributeOverride(name = "measurementDate", column = @Column(name = "TIMEDATE")),
        @AttributeOverride(name = "id", column = @Column(name = "MEASUREMENT_ID")) })
public class Measurement extends AbstractMeasurement {
      ....

    /**
     *
     */
    public Measurement() {
        init();
    }

    public Measurement(String kind, Patient patient) {
        super(patient, new Workflow(patient));
        System.out.println("patientID: " + patient.getId());
        setKind(kind);
        workflow.setKind(kind);
        init();
    }

    private void init() {
        values = new HashMap<String, AbstractMeasurementValue>();
    }
}

@Entity
@Table(name = "TOPCARE.WORKFLOW_VIEW")
@AttributeOverride(name = "id", column = @Column(name = "WORKFLOW_ID"))
public class Workflow extends DomainObject {

 ....

    @OneToOne
    @JoinColumn(name = "PATIENT_ID", referencedColumnName = "PATIENT_ID")
    private Patient patient;
    /**
     * INTERNAL!!!
     */
    public Workflow() {
    }

    public Workflow(Patient patient) {
        super();
        this.patient = patient;
        creationDate = new Date();
    }
}

Since the application may only write in the database through stored procedures and stored functions, and read the data on views. That's why i customized all involved DomainTypes by implementing the interface org.eclipse.persistence.config.DescriptorCustomizer. Here is the customize-method for type Measurement
public void customize(ClassDescriptor descriptor) throws Exception {
        if (MeasurementValue.class.equals(descriptor.getJavaClass())) {
            descriptor.setReadOnly();
            return;
        }
        descriptor.setDefaultInsertObjectQueryRedirector(new QueryRedirector() {

            /**
             *
             */
            private static final long serialVersionUID = 1L;

            @SuppressWarnings("unchecked")
            public Object invokeQuery(DatabaseQuery query, Record arguments,
                    Session session) {
                Measurement measurement = (Measurement) ((InsertObjectQuery) query)
                        .getObject();
                String measurementDateAsString = DateUtils
                        .changeDateTimeToDBFormat(measurement
                                .getMeasurementDate());
                StoredProcedureCall storedProcedureCall = null;
                Integer result = 0;
                Vector<Object> parameters = null;
               
                    storedProcedureCall = new StoredProcedureCall();
                    storedProcedureCall
                            .setProcedureName("topcare.top_treatment.spo2_measurement_write");
                    storedProcedureCall.addNamedOutputArgument(
                            "p_recordcard_id", "MEASUREMENT_ID", Integer.class);
                    storedProcedureCall.addNamedArgument("p_patient_id");
                    storedProcedureCall.addNamedArgument("p_patient_id");
                    storedProcedureCall.addNamedArgument("p_measurement_date");
                    storedProcedureCall.addNamedArgument("p_SpO2");
                    storedProcedureCall.addNamedArgument("p_Pulse");
                    storedProcedureCall.addNamedArgument("p_work_flow_id");
                    parameters = new Vector<Object>();
                    parameters.add(0, storedProcedureCall.getParameters()
                            .get(0));
                    parameters.add(1, measurement.getPatient().getId());
                    parameters.add(2, measurementDateAsString);
                    parameters.add(3, measurement
                            .getValue(MeasurementValueKind.BODYSPO2));
                    parameters.add(4, measurement
                            .getValue(MeasurementValueKind.BODYPULSE2));
                    parameters.add(5, measurement.getWorkflow().getId());
               
                logger.info("result: " + result);
                storedProcedureCall.setParameters(parameters);
                result = (Integer) ((DatabaseRecord) session
                        .executeSelectingCall(storedProcedureCall).get(0))
                        .get("MEASUREMENT_ID");
                measurement.setId(result); // line 754
                logger.info("generated measurementId:" + result); // line 755
                return result;    }

        });
}

After saving the measurement using i printed out the generated id via a logger (see line 755) and i see this id. Since i set the id by calling setId(see line 754). I don't understand why i get the following exception on the second attempt to save. That means the first save call function properly since i find the data in the database, but the second doesn't.

[EL Warning]: 2008.12.10 09:10:02.296--UnitOfWork(5651650)--Thread(Thread[http-8080-Processor25,5,main])--Exception [EclipseLink-7197] (Eclipse Persistence Services - 1.0.2 (Build 20081024)): org.eclipse.persistence.exceptions.ValidationException
Exception Description: Null primary key encountered in unit of work clone [topcare.domain.patient.measurement.Measurement@1f].
javax.persistence.RollbackException: Exception [EclipseLink-7197] (Eclipse Persistence Services - 1.0.2 (Build 20081024)): org.eclipse.persistence.exceptions.ValidationException
Exception Description: Null primary key encountered in unit of work clone [topcare.domain.patient.measurement.Measurement@1f].
    at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commitInternal(EntityTransactionImpl.java:102)
    at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:63)
    at topcare.domain.DAOFactory.commit(DAOFactory.java:510)
    at topcare.domain.UnitOfWork.commit(UnitOfWork.java:92)
    at topcare.service.MeasurementService.createMeasurement(MeasurementService.java:94)
    at topcare.ui.struts.measurement.MeasurementAction.execute(MeasurementAction.java:84)
    at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:431)
    at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:236)
    at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1196)
    at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:709)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:214)
    at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
    at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:198)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:152)
    at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
    at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:118)
    at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
    at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929)
    at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:799)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:705)
    at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:577)
    at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
    at java.lang.Thread.run(Thread.java:595)
Caused by: Exception [EclipseLink-7197] (Eclipse Persistence Services - 1.0.2 (Build 20081024)): org.eclipse.persistence.exceptions.ValidationException
Exception Description: Null primary key encountered in unit of work clone [topcare.domain.patient.measurement.Measurement@1f].
    at org.eclipse.persistence.exceptions.ValidationException.nullPrimaryKeyInUnitOfWorkClone(ValidationException.java:1305)
    at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.calculateChanges(DeferredChangeDetectionPolicy.java:84)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.calculateChanges(UnitOfWorkImpl.java:557)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1320)
    at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:159)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1002)
    at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commitInternal(EntityTransactionImpl.java:84)
    ... 35 more

Thanks for any help


Back to the top