Java – JPA @ ID and insertable = false, updatable = false throw exception
I'm using Oracle database. I have sequences and triggers to generate and store IDS before insertion
CREATE SEQUENCE CASE_SEQ START WITH 1001 INCREMENT BY 1 NOMAXVALUE; CREATE OR REPLACE TRIGGER CASE_TR_SEQ BEFORE INSERT ON CASE FOR EACH ROW BEGIN SELECT CASE_SEQ.NEXTVAL INTO :NEW.CASE_ID FROM DUAL; END; /
Then I have a simple entity with attributes:
@Id @Column(name = "CASE_ID",insertable = false,updatable = false) private Long caseId;
... when I try to build a project, I get:
Exception [EclipseLink-46] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DescriptorException Exception Description: There should be one non-read-only mapping defined for the primary key field [CASE.CASE_ID].
It works when I delete pluggable or updatable keywords I know many solutions how to use JPA to generate ID, and JPA can also use (call) Oracle sequence to set (generate) ID. but I try to understand why my solution is wrong Why can't I use these two keywords with the @ ID annotation? My idea is: I want to prohibit JPA from inserting or updating caseid
1) What is the right lotion? I should only use @ ID:
@Id @Column(name = "CASE_ID") private Long caseId;
Or better (safer) definition insertable = false:
@Id @Column(name = "CASE_ID",insertable = false) private Long caseId;
2) I understand that updatable = false for @ ID is meaningless (updating the primary key is meaningless, but the original SQL may be meaningful), but what does it mean (examples of benefits you have):
@Id @Column(name = "CASE_ID",updatable = false) private Long caseId;
Editor: April 13, 2012
I did some tests:
entity
@Id @Column(name = "CASE_ID") private Long caseId;
JPA log
INSERT INTO CASE (CASE_ID,CASE_DATE,INFO) VALUES (?,?,?) bind => [3 parameters bound]|#]
So this is not safe because JPA tries to store case_ ID (then replaced by the ID in the Oracle sequence of the trigger)
entity
@Id @Column(name = "CASE_ID",insertable = false) private Long caseId;
Create method
public void createCase(final Case caseData) { caseData.setCaseId(-1001L); em.persist(caseData); }
JPA log
INSERT INTO CASE (CASE_DATE,?) bind => [2 parameters bound]|#]
That's good because case_ ID is not part of the insert command
Case cannot be updated because of the comment ID_ ID:
public void update() { Case update = em.find(Case.class,1023L); update.setCaseId(1028L); } Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.ValidationException Exception Description: The attribute [caseId] of class [com.wordpress.kamiluv.jsfprototype.model.entity.Case] is mapped to a primary key column in the database. Updates are not allowed.
So now the last version looks the safest, right?
Solution
You are currently using JPA annotation to indicate that you have a @ ID column that cannot be inserted or updated in any way You must be able to set the ID before inserting or updating, but JPA does not know how to do this If you don't want to set the ID in the code, you need to use the @ generatedvalue annotation on the @ ID to tell JPA what strategy to use (one of table, sequence, identity, auto)