Goal
I wanted to have a simple database record with 2 primary keys in certain order, with a field that contains a simple value.
Java Persistent API with Spring
Using Java Persistent API (JPA), I thought that this would automatically set up primary keys in the order in the class, but this doesn't work the way intended.
@Entity
public class DataEntry {
@Id
private Integer deviceID;
@Id
private LocalDateTime measuredOn;
private Integer value;
/// getters and setters
}
Looking at this web page, I figured I need an ID Class.
https://www.baeldung.com/jpa-composite-primary-keys
public class DataEntryId implements Serializable {
private Integer deviceID;
private LocalDateTime measuredOn;
public DataEntryId(Integer deviceID, LocalDateTime measuredOn) {
this.deviceID = deviceID;
this.measuredOn = measuredOn;
}
/// equals and hashCode
}
With the ID Class defined, now that I can use it as an ID class in the annotation.
@Entity
@IdClass(DataEntryId.class)
public class DataEntry {
///....
}
Running the Spring Boot app with the above would create a table structure correctly when the app started.
mysql> desc data_entry;
+-------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+-------+
| deviceid | int | NO | PRI | NULL | |
| measured_on | datetime(6) | NO | PRI | NULL | |
| value | int | YES | | NULL | |
+-------------+-------------+------+-----+---------+-------+
mysql> show create table data_entry;
| data_entry | CREATE TABLE `data_entry` (
`deviceid` int NOT NULL,
`measured_on` datetime(6) NOT NULL,
`value` int DEFAULT NULL,
PRIMARY KEY (`deviceid`,`measured_on`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
Problem
However, in trying to store a data entry to this table, the following code generate an exception.
DataEntry dataEntry = new DataEntry();
dataEntry.setDeviceID(deviceId);
dataEntry.setMeasuredOn(measuredOn);
dataEntry.setValue(value);
dataEntryRepository.save(dataEntry);
Error:
org.hibernate.InstantiationException: Unable to locate constructor for embeddable : com.example.AccessData.DataEntryId
Solution
A subtle requirement in the ID class is that it has to have a default (no arg) constructor.
public DataEntryId() {
}
Top comments (0)