EclipseLink returns an object with a null primary key

Introduction

I have a problem that I find very mysterious. I searched on Google and StackOverflow, and did not find anyone who had a similar problem. I tried switching our persistence provider to Hibernate, but our code is too dependent on the features of EclipseLink to make it a practical debugging option. If this problem persists (ha, ha; Java EE pun), I can very well rewrite all the persistence code for Hibernate in case this helps.

Short version:

  • My ExperimentBlock entity is correctly stored in the database, and its primary auto-increment key is created correctly. However, when it is read from the database, EclipseLink provides me with an object with a zero primary key field. This causes a devastating error in production software.
  • ExperimentBlock inherits its primary key field with annotations, the receiver and the installer from its superclass PeriodResident . Several other subclasses of PeriodResident do the same, but EclipseLink loads its primary key correctly. This is the secret of this error: for each subclass of PeriodResident , the same field / getter / setter code is used, but ExperimentBlock is the only one that returns an EclipseLink with a zero primary key!
  • Running a JPQL query that selects ExpermentBlock returns them with zero primary keys. (Sadface.) However, executing a JPQL query that specifically selects the ExperimentBlock primary key field works correctly and returns a list of integer primary keys! This can be seen in the ExperimentBlock.findWithIdsBySchedule request below.

More details

GlassFish 3.1.2, EclipseLink 2.4.0, Java EE 6, MySQL 5.0.95-log

I do not get any exceptions. This issue occurs in a remote and local beans session.

The code should, please let me know if I should provide more details.

PeriodResident.java

(The superclass of the ExperimentBlock task. Here the primary key field is defined - uniqueID)

 package ohno; import ohno.ShiftDateConverter; import ohno.Shift; import ohno.Facility; import java.io.Serializable; import java.util.Date; import javax.persistence.Basic; import javax.persistence.Column; import javax.persistence.DiscriminatorColumn; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; import org.eclipse.persistence.annotations.Convert; import org.eclipse.persistence.annotations.Converter; @Converter(converterClass=ShiftDateConverter.class, name="ShiftDateConverter") @Entity @Inheritance(strategy = InheritanceType.JOINED) @Table(name="bs_blocks") @DiscriminatorColumn(name="block_type") public abstract class PeriodResident implements Serializable { private static final long serialVersionUID = 1L; public PeriodResident() { } /** * Sets the database unique id. * * @param uniqueID the new database unique id */ public void setUniqueID(Integer uniqueID) { this.uniqueID = uniqueID; } /** * Provides a useful super-constructor handling initialization of the first * and last Shifts of the PeriodResident time block, and the Facility * where it takes place. * * @param startShift The first Shift in the PeriodResident time block. * @param endShift The last Shift in the PeriodResident time block. * @param facility The Facility where the PeriodResident takes place. * @param uniqueID the unique id */ public PeriodResident(Shift startShift, Shift endShift, Facility facility, int uniqueID) { this.startShift = startShift; this.endShift = endShift; this.facility = facility; this.uniqueID = uniqueID; } /** * Instantiates a new period resident. * * @param startShift The first Shift in the PeriodResident time block. * @param endShift The last Shift in the PeriodResident time block. * @param facility The Facility where the PeriodResident takes place. */ public PeriodResident(Shift startShift, Shift endShift, Facility facility) { this(startShift, endShift, facility, null); } /** * Gets the facility. * * @return the Facility where the PeriodResident takes place. * * @see #setFacility(Facility) */ public Facility getFacility() { return facility; } /** * Gets the shifts. * * @return the total number of Shifts in the PeriodResident time block. * * @see #getStartShift() * @see #getEndShift() */ public int getShifts() { return endShift.getShiftsDifference(startShift); } /** * Gets the start shift. * * @return the first <code>Shift</code> in the PeriodResident time * block. * * @see #setStartShift(Shift) * @see #getShifts() */ public Shift getStartShift(){ return startShift; } /** * Gets the end shift. * * @return the last <code>Shift</code> in the PeriodResident time block. * * @see #setEndShift(Shift) * @see #getShifts() */ public Shift getEndShift(){ return endShift; } /** * Gets the database table unique ID for this particular PeriodResident, or null if * it hasn't one. * * @return this PeriodResident unique ID in the database. */ public Integer getUniqueID() { return uniqueID; } /** * sets this PeriodResident facility location with the given Facility. * * @param facility the PeriodResident new Facility. * * @see #getFacility() */ public void setFacility(Facility facility) { this.facility = facility; } /** * sets this PeriodResident time block new starting shift with the given * Shift. * * @param startShift the new starting shift. * * @see #getStartShift() */ public void setStartShift(Shift startShift) { this.startShift = startShift; } /** * sets this PeriodResident time block new ending shift with the given * Shift. * * @param endShift the new ending shift. * * @see #getEndShift() */ public void setEndShift(Shift endShift) { this.endShift = endShift; } public Schedule getSchedule() { return schedule; } public void setSchedule(Schedule schedule) { this.schedule = schedule; } protected void copyCharacteristics(PeriodResident original, PeriodResident clone) { clone.setStartShift(original.getStartShift().clone()); clone.setEndShift(original.getEndShift().clone()); clone.setFacility(original.getFacility()); clone.setSchedule(original.getSchedule()); } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "PeriodResident (Facility: " + facility + ") from " + startShift + " to " + endShift; } @Override public abstract Object clone(); public abstract String getResidentType(); @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final PeriodResident other = (PeriodResident) obj; if ((uniqueID == null && other.uniqueID != null) || (this.uniqueID != null && !this.uniqueID.equals(other.uniqueID))) { return false; } return true; } @Override public int hashCode() { if (uniqueID != null) { return uniqueID; } int hash = 7; hash = 73 * hash + (this.uniqueID != null ? this.uniqueID.hashCode() : 0); hash = 73 * hash + (this.startShift != null ? this.startShift.hashCode() : 0); hash = 73 * hash + (this.endShift != null ? this.endShift.hashCode() : 0); hash = 73 * hash + (this.facility != null ? this.facility.hashCode() : 0); hash = 73 * hash + (this.schedule != null ? this.schedule.hashCode() : 0); hash = 73 * hash + getClass().hashCode(); return hash; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ public boolean equivalent(PeriodResident other) { if (this == other) { return true; } if (other == null) { return false; } if (getClass() != other.getClass()) { return false; } if (endShift == null) { if (other.endShift != null) { return false; } } else if (!endShift.equals(other.endShift)) { return false; } if (facility == null) { if (other.facility != null) { return false; } } else if (!facility.equals(other.facility)) { return false; } if (startShift == null) { if (other.startShift != null) { return false; } } else if (!startShift.equals(other.startShift)) { return false; } if (schedule == null) { if (other.getSchedule() != null) { return false; } } else if (!schedule.equals(other.getSchedule())) { return false; } return true; } public Date getStartShiftDate() { return getStartShift().getTime(); } public Date getEndShiftDate() { return getEndShift().getTime(); } /** The database unique id. */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Basic(optional = false) @Column(name = "id") Integer uniqueID; /** The start shift of the PeriodResident. */ @Column(name = "start_time") @Convert(value="ShiftDateConverter") Shift startShift; /** The end shift of the PeriodResident.*/ @Column(name = "end_time") @Convert(value="ShiftDateConverter") Shift endShift; /** The facility where the PeriodResident lives. */ @ManyToOne @JoinColumn(name = "facility", referencedColumnName = "ID") Facility facility; @ManyToOne @JoinColumn(name = "schedule", referencedColumnName = "ID") private Schedule schedule; } 

ExperimentBlock.java

(Problem class ... note the last JPQL query that selects ExperimentBlock and its uniqueID . When this query is run, ExperimentBlock.uniqueId is null, and uniqueID is manually selected.)

 package ohno; import ohno.Experiment; import ohno.Role; import java.io.Serializable; import javax.persistence.DiscriminatorValue; import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.Table; import javax.persistence.Transient; /** * * @author Nick */ @Entity @Table(name = "bs_blocks_experiment") @NamedQueries({ @NamedQuery(name = "ExperimentBlock.findAll", query = "SELECT e FROM ExperimentBlock e"), @NamedQuery(name = "ExperimentBlock.findActualByExperiment", query = "SELECT e FROM ExperimentBlock e WHERE e.experiment = :experiment AND e.schedule.scheduleProperties.revision = :active ORDER BY e.schedule.id DESC, e.uniqueID DESC"), @NamedQuery(name = "ExperimentBlock.findByTime", query = "SELECT e FROM ExperimentBlock e WHERE e.startShift < :endTime AND e.endShift > :startTime and e.schedule = :schedule"), @NamedQuery(name = "ExperimentBlock.findWithIdsBySchedule", query = "SELECT e, e.uniqueID FROM ExperimentBlock e WHERE e.schedule = :schedule")}) @DiscriminatorValue(value = "EXPERIMENT_BLOCK") public class ExperimentBlock extends PeriodResident implements Serializable { private static final long serialVersionUID = 1L; // ######### // Some columns are inherited from PeriodResident! // ######### @Embedded protected Equipment equipment; @ManyToOne @JoinColumn(name = "experiment", referencedColumnName = "exp_id") private Experiment experiment; public ExperimentBlock() { } public Equipment getEquipment() { return equipment; } public void setEquipment(Equipment equipment) { this.equipment = equipment; } public Experiment getExperiment() { return experiment; } public void setExperiment(Experiment experiment) { this.experiment = experiment; } @Override public boolean equivalent(PeriodResident pr) { if (!super.equivalent(pr)) { return false; } ExperimentBlock other = (ExperimentBlock) pr; if (!getExperiment().equals(other.getExperiment())) { return false; } if (!getEquipment().equals(other.getEquipment())) { return false; } return true; } @Override public ExperimentBlock clone() { ExperimentBlock clone = new ExperimentBlock(); copyCharacteristics(this, clone); clone.setExperiment(getExperiment()); clone.setEquipment(equipment.clone()); return clone; } @Override public String getResidentType() { return RESIDENT_TYPE; } @Transient public static final String RESIDENT_TYPE = "ExperimentBlock"; @Override public String toString() { return "Experiment " + experiment + "\nChannel: " + getFacility() + "\nEquipment: " + getEquipment() + "\nFrom " + getStartShift() + "\nto " + getEndShift(); } /** * Gets an HTML string representation of this. * * @return the string */ public String toFancyString() { return "<html>Experiment <b>" + (experiment.isNoExperiment() ? "N/A" : experiment) + "</b><br>Channel: " + getFacility() + "<br>Equipment: " + getEquipment() + "<br>From: <b>" + getStartShift().toString(Role.BEGINNING) + "</b><br>To: <b>" + getEndShift().toString(Role.ENDING) + "</b><br>Shift Count: <b>" + getShifts() + "</b></html>"; } } 

&. WITH

So, I run the ExperimentBlock.getWithIdsBySchedule request in a bean session. I debug, set a breakpoint immediately after running this query and check the results. In the query results, I get the list [ ExperimentBlock , Integer ] - ExperimentBlock s' uniqueID - all null values; however, Integers - the manually requested uniqueID ExperimentBlock - are populated correctly.

Conclusion

Any ideas? That would really help me get rid. Again, let me know if there is more information that I could provide.

Addenda

  • Hackish (namely, "cludge") solutions to this problem are certainly welcome, as well as elegant solutions.
  • I checked the database (table definitions, foreign keys, etc.) and did not find anything special in ExperimentBlock that could explain my problem.
  • (From the comment below :) All other persistent ExperimentBlock properties load correctly. Loading ExperimentBlock with em.find() leads to the same problem. (Above, I loaded it from a JPQL query and as a property of another class, Schedule .)
+4
source share
1 answer

Odd. There must be something else with this object from working siblings.

A few things you could try to narrow down the problem,

  • use the uppercase "identifier" for the id column (and all other columns / tables).
  • try disabling weaving, or "eclipselink.weaving.internal"
  • try removing the clone / equals / hashCode methods.

Also enable logging and enable the SQL generated for the query and the full trace of the exception stack.

+4
source

Source: https://habr.com/ru/post/1434265/


All Articles