I'm facing an issue using EclipseLink (JPA2) on Weblogic 12. I searched for a solution over the internet but after spending too much hours without finding a fix, i decided to request you experience: maybe one of you can help me.
(This mapping works perfectly on WL 10.3.3 - EclipseLink (JPA1))
The basic user story : any 'power' users (called 'employers') of the application is able to make some requests (changes) about other users. You can consider that some 'employers' (HR, managers) can request some changes about other organization's employee (address change, transfer from a dept to another (or form a team to another team), hire a new employee, fire an employer, and so on...
My structure is the following:
Any kind of 'request' inherits from REQUEST (that an object and a table - that holds the PK of all king of requests). For example: HiringRequest, EmployerModificationRequest, FiringRequest, TransferRequest(which has subClasses/subTypes).
@Entity
@Converter(name = "code", converterClass = CodeConverter.class)
@Table(name = "REQUEST")
@Inheritance(strategy = JOINED)
@DiscriminatorColumn(name = "REQUEST_DISC", discriminatorType = STRING)
@SequenceGenerator(name = "REQUEST_SEQ", sequenceName = "Request_Sequence", allocationSize = 1, initialValue = 1)
public abstract class Request implements Serializable {
private static final long serialVersionUID = 5740148848518876165L;
@Id
@Column(name = "REQUEST_ID", nullable = false, length = 16)
@GeneratedValue(generator = "REQUEST_SEQ")
private long requestId;
...
}
@Entity
@Table(name = "TRANSFER_REQUEST")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@PrimaryKeyJoinColumn(name = "REQUEST_ID")
public abstract class TransferRequest extends Request {
private static final long serialVersionUID = 1L;
...
@OneToMany(cascade = ALL, mappedBy = "transferRequest")
private List<EmployeeInTransfer> employees;
public List<EmployeeInTransfer> getSourceEmployers() {
return employees;
}
public void setSourceEmployers(List<EmployeeInTransfer> inEmployees) {
for (EmployeeInTransfer employee : inEmployees) {
employee.setTransferRequest(this);
}
this.employees = inEmployees;
}
...
}
@Entity
@DiscriminatorValue("TEAM_CHANGE")
public class TeamChangeRequest extends TransferRequest {
private static final long serialVersionUID = 5747883857562212522L;
...
}
The EmployerIntransfer
@Entity
@Table(name = "EMPLOYEE_IN_TRANSFER")
@SequenceGenerator(name = "EMPLOYEE_IN_TRANSFER_SEQ", sequenceName = "Employee_In_Transfer_Sequence", allocationSize = 1, initialValue = 1)
public class EmployeeInTransfer implements Serializable {
private static final long serialVersionUID = 8987161385291888922L;
@Id
@Column(name = "EMPLOYEE_IN_TRANSFER_ID", nullable = false, length = 16)
@GeneratedValue(generator = "EMPLOYEE_IN_TRANSFER_SEQ")
private Long id;
@ManyToOne(optional = false, fetch=LAZY)
@JoinColumn(name = "TRANSFER_REQUEST_ID", nullable=false)
private TransferRequest transferRequest;
...
}
And the test class which is test the persistence:
@Test
public void teamChangePersistenceTest() {
DateTime creationOrReceptionDate = toDateTime(getDate(2010, 5, 5)).minusDays(5);
TransferRequest transferRequest = aTeamChangeRequest()
.withCreationDateTime(creationOrReceptionDate.toDate())
.build();
em.persist(transferRequest);
em.flush();
}
And the log shows this:
...
[EL Fine]: sql: 2016-01-22 11:02:06.962--INSERT INTO REQUEST ...
[EL Fine]: sql: 2016-01-22 11:02:06.986--INSERT INTO CATEGORY ...
[EL Fine]: sql: 2016-01-22 11:02:06.995--INSERT INTO EMPLOYEE_IN_TRANSFER ...
[EL Fine]: sql: 2016-01-22 11:02:07.041--SELECT 1 FROM DUAL
[EL Warning]: 2016-01-22 11:02:07.05--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.4.2.v20130514-5956486): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.BatchUpdateException: ORA-02291: integrity constraint (MYSCHEMA.FK_EIT_TR) violated - parent key not found
So... If is disabled the constraint, the persistence of the TeamChangeRequest occurs AFTER the EmployerInTransfer Objets and everything is fine. If the constraint is enabled (and that should be the right case), i'm facing a constraint violation due to the wrong order of the insert statements.
Request is the parent of the TransferRequest (TeamChangeRequest) which is responsible(parent) of the relation with EmployeeInTransfer (child).
How can i tweak EclipseLink to be sure that the TeamChangerequest object will be inserted BEFORE any EmployeeInTransfer statement?
Do you have any clue how can i fix it?
Because of the inheritance, the Request entity is the one with the primary key; JPA restricts entities to reference only primary keys and EclipseLink has optimized the inserts accordingly.
This means that the EmployeeInTransfer transferRequest relationship with a join column "TRANSFER_REQUEST_ID" should have a constraint to the REQUEST table, not the "TRANSFER_REQUEST" table.
That said, you can tell EclipseLink which field in particular it joins to in the join column rather then letting it default to the REQUEST table. Specify the table containing the referencedColumnName rather then let it default:
@ManyToOne(optional = false, fetch=LAZY)
@JoinColumn(name = "TRANSFER_REQUEST_ID", referencedColumnName="TRANSFER_REQUEST.REQUEST_ID", nullable=false)
private TransferRequest transferRequest;