5 Primary Key Mappings For JPA and Hibernate Every Developer Should Know
5 Primary Key Mappings For JPA and Hibernate Every Developer Should Know
With JPA and Hibernate you can do much more than just mapping a
simple, numeric primary key. You can:
choose between different strategies to generate unique primary
key values,
use UUIDs and generate their values,
map composite primary keys,
share primary key values across associations and
map natural IDs.
www.thoughts-on-java.org
5 Primary Key Mappings Every Developer Should Know
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
…
}
@Id
@GeneratedValue
private UUID id;
…
}
www.thoughts-on-java.org
5 Primary Key Mappings Every Developer Should Know
Manage Composite Primary Keys
JPA and Hibernate also provide multiple ways to map composite
primary keys that consist of multiple attributes. Let’s take a look at
my preferred option: the embedded id.
The embedded id approach uses an embeddable to map the primary
key attributes. An embeddable is a pure Java class that is annotated
with @Embeddable. It defines attribute mappings in a reusable way. If
you want to use it as an embedded id, you also need to implement
the equals and hashCode methods.
@Embeddable
public class AddressKey implements Serializable {
public AddressKey() {}
@Override
public int hashCode() {
int result = 1;
result = 31 * result + ((xId == null) ? 0 : xId.hashCode());
result = 31 * result + ((yId == null) ? 0 : yId.hashCode());
return result;
}
@Override
www.thoughts-on-java.org
public boolean equals(Object obj) {
5 Primary Key Mappings Every Developer Should Know
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AddressKey other = (AddressKey) obj;
if (xId == null) {
if (other.xId != null)
return false;
} else if (!xId.equals(other.xId))
return false;
if (yId == null) {
if (other.yId != null)
return false;
} else if (!yId.equals(other.yId))
return false;
return true;
}
}
You can then use the embeddable class as the type of your primary
key attribute and annotate it with @EmbeddedId. The embeddable
and all its attributes become part of the entity. It follows the same
lifecycle, and all its attributes get mapped to the database table that’s
mapped by the entity.
www.thoughts-on-java.org
5 Primary Key Mappings Every Developer Should Know
@Entity
public class Address {
@EmbeddedId
private AddressKey id;
@OneToOne(mappedBy = "address")
private Person person;
...
}
www.thoughts-on-java.org
5 Primary Key Mappings Every Developer Should Know
@Entity
public class Manuscript {
@Id
private Long id;
@OneToOne
@JoinColumn(name = "id")
@MapsId
private Book book;
...
}
www.thoughts-on-java.org
5 Primary Key Mappings Every Developer Should Know
Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@NaturalId
private String isbn;
…
}
After you’ve done that, you can use the byNaturalId method on
Hibernate’s Session interface to create a query that loads an entity by
its natural id.
In the next step, you need to provide the value of the natural id by
calling the using method for each attribute that’s part of the natural
id. In this example, the natural id only consists of the isbn attribute,
which I reference using the JPA metamodel class of the Book entity.
And after you provided the natural id value, you can call the load
method to execute the query.
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Session session = em.unwrap(Session.class);
Book b = session.byNaturalId(Book.class)
.using(Book_.isbn.getName(), “978-0321356680”).load();
www.thoughts-on-java.org