avatarIvan Franchin

Summary

The content provides an in-depth explanation of implementing a Many-to-Many relationship in JPA with a simple primary key, illustrated through associating Writer and Book entities.

Abstract

The web content is part of a series discussing JPA relationships, focusing on the Many-to-Many association with a simple primary key. It guides readers through the process of mapping Writer and Book entities using JPA and Hibernate. The article includes a detailed explanation of the code required to establish this relationship, including the use of annotations such as @Entity, @ManyToMany, and @JoinTable. The author, Ivan Franchin, has created a GitHub repository with examples for each relationship type, aiming to enhance developers' understanding of JPA relationships. The article also demonstrates how JPA/Hibernate generates the corresponding tables in a PostgreSQL database and concludes by inviting readers to engage with the content and follow the author's work on various platforms.

Opinions

  • The author expresses personal difficulty in correctly implementing JPA relationships, indicating a common challenge among developers.
  • Ivan Franchin emphasizes the educational value of the provided GitHub repository, suggesting it as a useful resource for developers.
  • The article reflects the author's belief in the importance of understanding JPA relationships for efficient database schema management.
  • By offering a step-by-step explanation and showcasing the generated PostgreSQL tables, the author conveys a commitment to clarity and practical learning.
  • The call to action for reader engagement and support suggests the author values community interaction and feedback as part of the educational process.

Spring Boot | Spring Data JPA

Understanding Relationships in JPA: Many-to-Many with Simple Primary Key

Discussing “Many-to-Many with Simple Primary Key” and examining how JPA/Hibernate generates the corresponding tables

Photo by Tom Hermans on Unsplash

As mentioned in the introductory article of this series, I’ve faced difficulties in implementing JPA relationships correctly in my applications.

To enhance my understanding of them, I developed a GitHub repository called ivangfr/spring-data-jpa-relationships, containing simple examples for each relationship type.

In this series of articles, we will demonstrate each JPA relationship type by presenting the necessary code to map the entities and examining how JPA/Hibernate generates the tables.

I hope you find these articles and the GitHub repository helpful.

Today, we will talk about “Many-to-Many with Simple Primary Key”. So, let’s get started!

Many-to-Many with Simple Primary Key

In this example, we will associate Writer and Book entities. A writer can write zero, one, or more books, and a book can be written by one or more writers.

Below is the desired database model we aim to achieve.

This is the complete and final code. Next, we will explain it in detail.

@Entity
@Table(name = "books")
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinTable(name = "books_writers",
            joinColumns = @JoinColumn(name = "book_id"),
            inverseJoinColumns = @JoinColumn(name = "writer_id")
    )
    private Set<Writer> writers = new LinkedHashSet<>();

    @Column(nullable = false)
    private String name;

    // getters and setters
}

@Entity
@Table(name = "writers")
public class Writer {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    @ManyToMany(mappedBy = "writers")
    private Set<Book> books = new LinkedHashSet<>();

    @Column(nullable = false)
    private String name;

    // getters and setters
}

We create two classes, Book and Writer, and use the @Entity annotation to indicate that these classes correspond to database tables.

By default, the table name would be the same as the entity name, but we want them to be in plural form. We can achieve this by using the @Table annotation, where we specify the desired table name. For the Book entity, we use “books”, and for the Writer entity, we use “writers”.

Next, we add the id field of type Long and the name field of type String to both Writer and Book classes.

To ensure that the name field in the Book and Writer entities cannot have null values, we add the @Column(nullable = false) annotation to it. This annotation tells JPA that the corresponding database column should be defined as NOT NULL.

For theid field in both Book and Writer entities, we add the annotations: @Id and @GeneratedValue(strategy = GenerationType.SEQUENCE). The @Id annotation indicates that the field is the primary key for the entity, while the @GeneratedValue annotation specifies the strategy for generating the ID.

The @ManyToMany annotation is used to specify a many-to-many relationship between two entities. In this case, the Book entity has a Set of Writer objects called writers, and the Writer entity has a Set of Book objects called books.

The cascade attribute is used to specify the operations that should be cascaded to the associated Writer entities when a Book entity is persisted or updated. In this example, the CascadeType.PERSIST and CascadeType.MERGE options are used to persist and merge associated Writer entities.

The @JoinTable annotation is used to define the intermediate table for the many-to-many relationship. In this example, the name of the intermediate table is books_writers. The joinColumns attribute specifies the foreign key column name in the intermediate table that references the primary key column of the Book entity, and the inverseJoinColumns attribute specifies the foreign key column name in the intermediate table that references the primary key column of the Writer entity.

The mappedBy attribute, present in the @ManyToMany the annotation in Writer class, is used to specify that the relationship between Book and Writer is bidirectional, and that the Writer entity is the inverse side of the relationship. This means that the relationship is actually managed by the Book entity, and that the writers property in the Book entity maps the relationship.

Lastly, let’s describe the tables in PostgreSQL terminal.

jparelationshipsdb=# \d books
                       Table "public.books"
 Column |          Type          | Collation | Nullable | Default
--------+------------------------+-----------+----------+---------
 id     | bigint                 |           | not null |
 name   | character varying(255) |           | not null |
Indexes:
    "books_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "books_writers" CONSTRAINT "fkay1r7fvj70dj8s798rwygkocl" FOREIGN KEY (book_id) REFERENCES books(id)



jparelationshipsdb=# \d writers
                      Table "public.writers"
 Column |          Type          | Collation | Nullable | Default
--------+------------------------+-----------+----------+---------
 id     | bigint                 |           | not null |
 name   | character varying(255) |           | not null |
Indexes:
    "writers_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "books_writers" CONSTRAINT "fkt3u2vdjmd25510aii68qshl2j" FOREIGN KEY (writer_id) REFERENCES writers(id)



jparelationshipsdb=# \d books_writers
            Table "public.books_writers"
  Column   |  Type  | Collation | Nullable | Default
-----------+--------+-----------+----------+---------
 book_id   | bigint |           | not null |
 writer_id | bigint |           | not null |
Indexes:
    "books_writers_pkey" PRIMARY KEY, btree (book_id, writer_id)
Foreign-key constraints:
    "fkay1r7fvj70dj8s798rwygkocl" FOREIGN KEY (book_id) REFERENCES books(id)
    "fkt3u2vdjmd25510aii68qshl2j" FOREIGN KEY (writer_id) REFERENCES writers(id)

Both the books and writers tables have their own id column set as Primary Key. To establish the many-to-many relationship between them, a new table called books_writers was created, with book_id and writer_id columns as its composite Primary Key. The book_id column serves as a Foreign Key to the id column in the books table, while the writer_id column serves as a Foreign Key to the id column in the writers table.

Conclusion

In this series of articles, we are exploring the four different types of relationships in JPA: one-to-one, one-to-many / many-to-one, and many-to-many. By presenting simple examples for each type of relationship and providing necessary code to map the entities, we hope to help developers to gain a better understanding of the JPA relationships.

Support and Engagement

If you enjoyed this article and would like to show your support, please consider taking the following actions:

  • 👏 Engage by clapping, highlighting, and replying to my story. I’ll be happy to answer any of your questions;
  • 🌐 Share my story on Social Media;
  • 🔔 Follow me on: Medium | LinkedIn | Twitter | GitHub;
  • ✉️ Subscribe to my newsletter, so you don’t miss out on my latest posts.
Jpa
Spring Data Jpa
Technology
Database
Relational Databases
Recommended from ReadMedium