JPA
Hibernate
Primary Key
Database Annotations
Java

Which annotation should I use IdClass or EmbeddedId

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

When working with JPA (Java Persistence API), representing primary keys in entities is a common task. In cases of simple keys, this is straightforward, but composite keys can present challenges. Two approaches in JPA for defining composite keys are using @IdClass and @EmbeddedId, each having specific use cases, benefits, and limitations.

Composite Keys in JPA

In a relational database, a composite key is a primary key that consists of more than one column. While it might be necessary for certain database designs, mapping these composite keys correctly in JPA takes careful consideration.

Using @IdClass

The @IdClass annotation enables you to define a composite primary key by creating a separate key class. This class must implement Serializable and define the composite key fields just as they appear in the entity.

Example:

Here's an entity example using @IdClass:

java
1@Entity
2@IdClass(EmployeeId.class)
3public class Employee {
4    @Id
5    private Long empId;
6
7    @Id
8    private Long deptId;
9    
10    private String name;
11    
12    // Getters and setters
13}
14
15public class EmployeeId implements Serializable {
16    private Long empId;
17    private Long deptId;
18
19    // Default constructor, equals, and hashCode
20}

Key Points:

  • Separate Class: A separate class (EmployeeId) is used to represent the composite key.
  • Annotations: The composite key class doesn't use any JPA annotations.
  • Code Complexity: More verbose as the fields need to be duplicated in both the entity and the key class.
  • Readability: May reduce code readability due to class duplication.

Using @EmbeddedId

The @EmbeddedId approach encourages you to encapsulate the composite key within a single embeddable class annotated with @Embeddable. This technique keeps the key fields together and increases readability.

Example:

Here's an entity example using @EmbeddedId:

java
1@Entity
2public class Employee {
3    @EmbeddedId
4    private EmployeeId id;
5    
6    private String name;
7    
8    // Getters and setters
9}
10
11@Embeddable
12public class EmployeeId implements Serializable {
13    private Long empId;
14    private Long deptId;
15
16    // Default constructor, equals, and hashCode
17}

Key Points:

  • Single Class for Key: The composite key is contained within one class annotated with @Embeddable.
  • Simplicity: The entity class has a clean structure as it directly uses the composite key class.
  • Integration: Easier to integrate with entities due to contained encapsulation.
  • Readability: Enhanced readability because all key fields are kept together.

Key Considerations

Choosing between @IdClass and @EmbeddedId depends on several factors:

  • Encapsulation: @EmbeddedId provides better encapsulation since the key class is contained within the entity.
  • Redundancy: @IdClass requires duplication of key fields, increasing redundancy.
  • Legacy Support: In cases where working with older codebases or strict separation is required, @IdClass might be necessary.
  • Readability and Maintenance: The @EmbeddedId approach often enhances readability and maintainability.

Comparison Table

Below is a concise comparison between the two approaches:

Feature@IdClass@EmbeddedId
EncapsulationSeparate key and entity classesKey encapsulated in entity in a single class
Annotation UsageNo JPA annotations in key classUse of @Embeddable annotation
Code RedundancyDuplication of key fieldsNo duplication of key fields
Ease of UseCan be verboseGenerally more concise
IntegrationRequires explicit managementDirectly integrated into entity
ReadabilityMore complex and clutteredCleaner and more readable

Conclusion

Both @IdClass and @EmbeddedId offer mechanisms for handling composite keys in JPA, but they suit different scenarios. If your priority is encapsulation and readability, @EmbeddedId is generally the preferred choice. On the other hand, @IdClass can be useful in special cases, especially if separation between the key and entity classes is desired due to legacy requirements or specific architectural needs.

Ultimately, the choice between these two annotations should consider factors like project requirements, readability, encapsulation, existing codebase constraints, and personal or team preferences.


Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.