Engineering Full Stack Apps with Java and JavaScript
A composite key is a primary key composed of multiple columns.
When you are creating a composite key, your persistent class must override the equals() and hashCode() method. This is required for for Hibernate caching to work correctly. It must also implement the Serializable interface.
Best way to do this is to create a class with all your composite key fields, mark it as @Embeddable and then annotate a field of that class type with @Id in your entity class.
@Embeddable
public class MyCompositeID implements Serializable {
int field1;
int field2;
…
The entity is defined as follows:
@Entity
public class Sample {
@Id
MyCompositeID id;
…
Hibernate also provides some alternative approaches for implementing composite keys, but the above approach is more preferred.
You can use the @Id annotation over multiple fields.
@Entity
public class Employee {
@Id
Long department;
@Id
Long empId;
…
In a mapping file, you can use <composite-id> to define the object ID, which consists of two properties:
<hibernate-mapping>
<class name="Emplyee" table="Employee">
<composite-id>
<key-property name="department" type="long" column="DEPT" />
<key-property name=" empId " type="long" column=" EMPID "/>
</composite-id>
…
</class>
</hibernate-mapping>
To retrieve a specified object from the database using the load() or get() methods, you will need to pass a newly created Employee object with the key fields set.
Employee emp = new Employee();
//set key fields
Employee employee = (Employee) session.get(Employee.class, emp);
As Hibernate requires any ID class to implement the java.io.Serializable interface, your persistent class should implement Serializable interface.
It might not be a good thing to pass the complete persistent class object to retrieve records. A better way is to extract the fields that form the ID as a separate class.
The fields will be still present in the persistent class, and the external class is created with the same ID property names and types as in the persistent class. You also need to specify this external class as @IdClass in the persistent class.
Example ID class:
public class EmployeeId implements Serializable {
Long department;
Long empId;
…
You then need to modify the persistent class to specify this new ID class using @IdClass annotation:
@Entity
@IdClass(EmployeeId.class)
public class Employee {
@Id
Long department;
@Id
Long empId;
…
The mapping definition should also be modified to use the ID class:
<hibernate-mapping>
<class name="Employee" table="employee">
<composite-id name="id" class=" EmployeeId">
<key-property name="department" type="string" column="DEPT" />
<key-property name="empId" type="string" column=" EMPID "/>
</composite-id>
…
</class>
</hibernate-mapping>
Now, to retrieve an Employee object, you can pass in an instance of EmployeeId type:
EmployeeId employeeId = new EmployeeId(1,101);
Employee employee = (Employee) session.get(Employee.class, employeeId);
For Hibernate caching to work correctly, you need to override the equals() and hashCode() methods of your custom ID class.