Explain Codes LogoExplain Codes Logo

How to map a composite key with JPA and Hibernate?

java
orm-software
hibernate
jpa
Nikita BarsukovbyNikita Barsukov·Nov 1, 2024
TLDR

Map a composite key in JPA using the @Embeddable annotation for the key class, and the @EmbeddedId annotation in your main entity. For instance:

@Embeddable public class CompositeKey implements Serializable { //because two heads are better than one private Long partOne; private Long partTwo; // getters, setters are the "public relations" of the Java world // for equals and hashCode, think of them as your identity-card } @Entity public class MyEntity { @EmbeddedId //unity in diversity private CompositeKey id; // other fields go here… // feels like Alice in Wonderland, right? }

This ensures uniqueness and identification for entity instances when a single primary key isn't enough.

Delving deeper with @Embeddable and @EmbeddedId

With the @EmbeddedId approach, your CompositeKey class must be public, serializable, and contain a public no-arg constructor. The importance? Hibernate needs this set-up to instantiate and use the composite key class properly.

Further, implement equals() and hashCode() methods. This guaranties perfect fitting in JPA primary keys universe!

Be aware, with @EmbeddedId, you structure queries in a different way than @IdClass. You handle an embedded object (higher level thinking here!), not just fields in the primary entity. So in JPQL queries, make sure you recognize this unique structure.

Pragmatic benefits and considerations

@EmbeddedId comes with superior domain modeling bonus, making code relationships transparent. Not to forget the ease it provides while dealing with bi-directional relationships.

A small caution though. Be careful with lazy loading and Hibernate. Proxy classes might affect equality checks. For smooth sailing, make your equals() method Hibernate proxy-friendly.

Getting hands dirty with Composite Keys

Auto-mapping with development tools

Want to break-free from the manual coding of composite keys? Then get friendly with reverse engineering and development tools like Netbeans Entities. They can generate @Embeddable classes for you. Goodbye, repetitive boilerplate code!

Implementing Liskov's principle in equals()

In the equals() method, adhere to the Liskov Substitution Principle because our superclass and subclass should be as interchangeable as superhero costumes. Why does it matter? Because it upholds class hierarchy integrity, especially as we play in the realm of inheritance and composite keys.

Relation mapping with @ManyToOne and @JoinColumns

When composite key flirts with another entity, @ManyToOne and @JoinColumns can facilitate this relationship. This is ORM-software, playing the emcee at the party of entities and relationships.

@Embeddable public class CompositeKey implements Serializable { //... @ManyToOne @JoinColumns({ @JoinColumn(name = "FOREIGN_KEY_PART1", referencedColumnName = "ID_PART1"), @JoinColumn(name = "FOREIGN_KEY_PART2", referencedColumnName = "ID_PART2") }) //here are "compound eyes" of our composite key class private OtherEntity relatedEntity; }