Composite keys are a group of columns in the database, whose values together make a unique value. When using Hibernate or JPA applications there are two main strategies to map a Composite Primary Key.
Mapping a Composite key with an @IdClass
The name of the class is indicated as the value of the class attribute of the IdClass element, as
shown in this example:
@Entity @IdClass(PersonId.class) public class Person { @Id String name; @Id String surname; String address; String email; // Getter Setters and Constructors }
As you can see, the Compound keys are annotated with @Id and we need to provide an @IdClass:
public class PersonId implements Serializable { String name; String surname; // Constructors // Getters /Setters equals and hashcode public PersonId(String name, String surname) { this.name = name; this.surname = surname; } }
If using a Repository pattern to access your data, the compound key will be used as Type (instead of the Integer id field):
public interface PersonRepository extends CrudRepository<Person, PersonId> { List<Person> findBySurname(String surname); }
Mapping a Composite key with an EmbeddedId
An embedded type is marked as such by adding the @Embeddable annotation to the class definition.
This annotation serves to distinguish the class from other regular Java types. Once a class has been
designated as embeddable, then its fields and properties will be persistable as part of an entity.
Here is a Class which uses an @Embeddable annotation:
@Entity public class Customer { @EmbeddedId private CustomerEmbeddable customerPK; String address; String email; // Getter Setters and Constructors }
As you can see, the compound key fields are not included in the Entity class. The CustomerEmbeddable class follows here:
@Embeddable public class CustomerEmbeddable implements Serializable { String name; String surname; // Constructors // Getters /Setters equals and hashcode public CustomerEmbeddable(String name, String surname) { this.name = name; this.surname = surname; } }
You should as well adapt your Repository class to use the Embeddable primary key:
public interface CustomerRepository extends CrudRepository<Customer, CustomerEmbeddable> { List<Customer> findByEmail(String email); }
So, which one should you choose? from the Database point of view, no changes are required when choosing one strategy or another
The @EmbeddedId
strategy does not include the primary key fields in the Entity and thus communicates more clearly that the key is a composite key. Therefore, if you are using directly your Entity in your Controllers it makes more sense to use it. On the other hand, if using a DTO layer to hide the complexity of the Entity you can opt for the @IdClass which has the advantage to be less verbose when using HQL queries.
For example, compare:
select p.name from Person p
With:
select c.customerEmbeddable.name from Customer c
In conclusion, we have covered the two main strategies to map a compound primary key in a Hibernate / JPA application.
Source code for this example: https://github.com/fmarchioni/masterspringboot/tree/master/jpa/composite-pk