In the previous tutorial, I showed you how to represent a Composite Primary Key in JPA using the @Embeddable annotation. In addition to this, we also have a way to represent the Composite Primary Key in JPA which is using the @IdClass annotation. How is it in details? Let’s find out in this tutorial.
First, I also create a Maven project as an example:
I will use Hibernate as JPA implementation so I will add Hibernate dependency as follows:
1 2 3 4 5 |
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.2.12.Final</version> </dependency> |
MySQL Connector:
1 2 3 4 5 |
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>6.0.6</version> </dependency> |
Project Lombok:
1 2 3 4 5 6 |
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.18</version> <scope>provided</scope> </dependency> |
Table student:
1 2 3 4 5 6 |
CREATE TABLE `student` ( `id` int(11) NOT NULL, `code` int(11) NOT NULL, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`, `code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
To represent Composite Primary Key of student table, we first create a class containing the information of the two primary key columns. The difference from using @Embeddable annotation is that we do not need to use any annotations in this class. The content of this class is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package com.huongdanjava.jpaidclass; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; import java.io.Serializable; @EqualsAndHashCode @Getter @Setter @AllArgsConstructor public class StudentId implements Serializable { private Integer id; private Integer code; } |
Note that this object must also be implemented in the Serializable interface, and the equals() and hashCode() methods must be declared.
Next we will declare the Student entity using the @IdClass annotation with the StudentId object as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package com.huongdanjava.jpaidclass; import lombok.Getter; import lombok.Setter; import javax.persistence.*; @Entity @Table @Setter @Getter @IdClass(StudentId.class) public class Student { @Id private Integer id; @Id private Integer code; @Column private String name; } |
As you can see, we will declare the @IdClass annotation with the value of the class name containing the Composite Primary Key definition. And another note is that in the Student entity declaration, we must declare the Primary Key columns with the annotation @Id.
That’s it! Now I will make an example to see how it works.
I will add the configuration file for JPA, persistence.xml, located in the /src/main/resources/META-INF directory with the following contents:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence_2_1.xsd"> <persistence-unit name="jpaexample" transaction-type="RESOURCE_LOCAL"> <class>com.huongdanjava.jpaidclass.Student</class> <exclude-unlisted-classes>true</exclude-unlisted-classes> <properties> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" /> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpaexample" /> <property name="javax.persistence.jdbc.user" value="root" /> <property name="javax.persistence.jdbc.password" value="123456" /> <property name="hibernate.format_sql" value="true" /> <property name="hibernate.use_sql_comments" value="true" /> </properties> </persistence-unit> </persistence> |
Next, I create a new class for example. In this class, we will use the EntityManager object to look up the table student, which records the primary key columns with certain values. Id will now be the StudentId object.
As follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
package com.huongdanjava.jpaidclass; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; public class Application { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaexample"); EntityManager em = emf.createEntityManager(); Student student = em.find(Student.class, new StudentId(1, 123)); System.out.println("Student name: " + student.getName()); em.close(); emf.close(); } } |
If in the database, I have the following data:
then at runtime, the results will look like this: