1. Overview

In this short tutorial, we’ll learn how to use the Hibernate annotation @MapsId to implement the shared primary key strategy.

First, we’ll start with some insight into what @MapsId is. Then, we’ll demonstrate how to use it in practice.

2. @MapsId Annotation

JPA/Hibernate provides several convenient annotations that we can use to do all the heavy lifting of object-relational mapping. Among these annotations, we find @MapsId.

In short, this annotation simplifies one-to-one relationships, allowing two entities to share the same primary key. It helps implement the shared primary key strategy by telling Hibernate to map the primary key of a child entity to the primary key of its associated parent entity.

Now that we know what @MapsId is, let’s go down the rabbit hole and see how to use it in practice.

3. Setting up the Application

To illustrate the usage of this annotation, we need to set up a basic example. Let’s consider a classic situation where we have two tables in the database, Person and Address. Here, we’ll assume that the two tables share a one-to-one relationship. Each person has one address and each address belongs to one person.

Now, we’ll create the corresponding JPA entities for the two tables. Let’s start with the Person entity class:

@Entity
public class Person {
    @Id
    private int id;
    private String firstName;
    private String lastName;
    @OneToOne(mappedBy = "person")
    private Address address;

    // standards getters and setters
}

In this example, we define a person by their identifier, first name, last name, and address.

Typically, we use the @Entity annotation to denote that the Person class is a JPA entity. Moreover, @Id marks the field that represents the primary key. Furthermore, @OneToOne, as the name implies, defines the one-to-one association with the Person entity as the non-owning side.

Next, let’s create the Address entity class:

@Entity
public class Address {

    @Id
    private int id;
    private String street;
    private String city;
    private int zipode;
    @OneToOne
    @JoinColumn(name = "id")
    @MapsId
    private Person person;

    // standards getters and setters
}

Similarly, we used the same annotations to map our table Address. The important part is the person attribute marked by the @MapsId annotation.

Here, we instruct Hibernate to use the primary key value of the Person entity as the primary key value of the Address entity. In other words, P**erson and Address tables will have the same primary key values.

4. Usage Example

As a basic and mostly evident example, we’ll try to insert a Person instance with a specific identifier. Then, we’ll insert an Address object without specifying an id and see what happens:

@Test
void givenPersonEntityWithIdentifier_whenAddingAddress_thenPersistWithSameIdentifier() {
    int personId = 3;
    Person person = new Person();
    person.setId(personId);
    person.setFirstName("Azhrioun");
    person.setLastName("Abderrahim");
    session.persist(person);
    Address address = new Address();
    address.setStreet("7 avenue berlin");
    address.setCity("Tamassint");
    address.setZipode(13000);
    address.setPerson(person);

    session.persist(address);
    Address persistedAddress = session.find(Address.class, personId);

    assertThat(persistedAddress.getId()).isEqualTo(personId);
}

As we can see, Hibernate inserts a new record into the Address table with the same identifier as the given person even though we don’t specify an ID in the first place.

In a nutshell, the @MapsId helps to easily map a one-to-one relationship where the foreign key in the child entity acts also as a primary key allowing both entities to share the same primary key.

Another important caveat is that without @MapsId, we’d define two columns for the foreign and primary keys in the child entity. So, with @MapsId, we can avoid this duplication by providing a single mapping for both.

5. Conclusion

In this article, we learned how to use the @MapsId annotation to implement the shared primary key strategy when using one-to-one relationships.

As always, the full source code of the examples is available over on GitHub.