Hibernate / JPA Many to Many Mappings

Learn to create and manage many-to-many relationships between entities in a hibernate/JPA-based applications using @ManyToMany annotation.

A many-to-many association is made between two entities where one entity can be associated with multiple other instances of the other entity. For example, for a subscription service, SubscriptionEntity and ReaderEntity can be two types of entities. A given subscription can have multiple readers, whereas a reader can subscribe to multiple subscriptions.

1. Design Overview

The @ManyToMany association requires a link table that joins two entities. Note that @ManyToMany can be either unidirectional or bidirectional.

To demonstrate many to many mapping using hibernate annotations, we will associate two entities i.e. ReaderEntity and SubscriptionEntity. Their database schema is given in the image. Using these tables, any application can save multiple associations between readers and subscriptions.

many-to-many-hibernate-mapping-3294174

1.1. Unidirectional

This is the preferred approach in most cases. We should apply @ManyToMany annotation only on the owning side of the relationship.

public class SubscriptionEntity {

      @Id
      @Column(name = "ID")
      private Integer subscriptionId;

      @Column
      private String subscriptionName;

      @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
      private Set<ReaderEntity> readers;
}

public class ReaderEntity {
      @Id
      @Column(name = "ID")
      private Integer readerId;

      @Column
      private String email;
}

1.2 Bidirectional

A bidirectional @ManyToMany association has an owning and a mappedBy side.

public class SubscriptionEntity {

      @Id
      @Column(name = "ID")
      private Integer subscriptionId;

      @Column
      private String subscriptionName;

      @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
      private Set<ReaderEntity> readers;
}

public class ReaderEntity {
      @Id
      @Column(name = "ID")
      private Integer readerId;

      @Column
      private String email;

      @ManyToMany(mappedBy = "readers")
      private Set<ReaderEntity> subscriptions;
}

2. Owning Side Entity

The relationship owning entity is the entity that is responsible make making the association and maintaining it. In our case, I am making ReaderEntity the owner entity. @JoinTable annotation has been used to make this association.

The link table is controlled by the owning side. When an entity is removed from the @ManyToMany collection, Hibernate simply deletes the joining record in the link table.

Avoid using CascadeType.REMOVE because it will propagate beyond the link table. Since the mapped entities (to-be-deleted) might be referenced by other entities on the parent-side, the automatic removal might end up in a ConstraintViolationException.

So, the good practice is just to remove the parent record and Hibernate will remove the associated link records.

@Entity(name = "ReaderEntity")
@Table(name = "READER", uniqueConstraints = {
    @UniqueConstraint(columnNames = "ID"),
    @UniqueConstraint(columnNames = "EMAIL")})
public class ReaderEntity implements Serializable {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "ID", unique = true, nullable = false)
  private Integer readerId;

  @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
  @JoinTable(name = "READER_SUBSCRIPTIONS", joinColumns =
                  {@JoinColumn(referencedColumnName = "ID")}
      , inverseJoinColumns = {@JoinColumn(referencedColumnName = "ID")})
  private Set<SubscriptionEntity> subscriptions;

  //Other fields, getters, setters are hidden for brevity
}

3. Mapped Entity

Our mapped entity is SubscriptionEntity which is mapped to ReaderEntity using “mappedBy” attribute. It is done in the bi-directional association.

@Entity(
@Table(name = "SUBSCRIPTION", uniqueConstraints = {
            @UniqueConstraint(columnNames = "ID")})
public class SubscriptionEntity implements Serializable 
{
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      @Column(name = "ID", unique = true, nullable = false)
      private Integer subscriptionId;

      @Column(name = "SUBS_NAME", unique = true, nullable = false, length = 100)
      private String subscriptionName;
      
      @ManyToMany(mappedBy = "subscriptions")
      private Set<ReaderEntity> readers;

      //Other fields, getters, setters are hidden for brevity
}

4. Demo

Now, it’s time to test the code. I have written the following code to test the above entities and their many-to-many relationship.

// Add subscription
SubscriptionEntity subOne = new SubscriptionEntity();
subOne.setSubscriptionName("Entertainment");

SubscriptionEntity subTwo = new SubscriptionEntity();
subTwo.setSubscriptionName("Horror");

Set<SubscriptionEntity> subs = new HashSet<SubscriptionEntity>();
subs.add(subOne);
subs.add(subTwo);

// Add readers
ReaderEntity readerOne = new ReaderEntity();
readerOne.setEmail("demo-user1@mail.com");
readerOne.setFirstName("demo");
readerOne.setLastName("user");

ReaderEntity readerTwo = new ReaderEntity();
readerTwo.setEmail("demo-user2@mail.com");
readerTwo.setFirstName("demo");
readerTwo.setLastName("user");

Set<ReaderEntity> readers = new HashSet<ReaderEntity>();
readers.add(readerOne);
readers.add(readerTwo);

readerOne.setSubscriptions(subs);
readerTwo.setSubscriptions(subs);

session.save(readerOne);
session.save(readerTwo);

Program Output:

Hibernate: insert into READER (EMAIL, FIRST_NAME, LAST_NAME) values (?, ?, ?)
Hibernate: insert into SUBSCRIPTION (SUBS_NAME) values (?)
Hibernate: insert into SUBSCRIPTION (SUBS_NAME) values (?)
Hibernate: insert into READER (EMAIL, FIRST_NAME, LAST_NAME) values (?, ?, ?)
Hibernate: insert into READER_SUBSCRIPTIONS (readers_ID, subscriptions_ID) values (?, ?)
Hibernate: insert into READER_SUBSCRIPTIONS (readers_ID, subscriptions_ID) values (?, ?)
Hibernate: insert into READER_SUBSCRIPTIONS (readers_ID, subscriptions_ID) values (?, ?)
Hibernate: insert into READER_SUBSCRIPTIONS (readers_ID, subscriptions_ID) values (?, ?)

In this example, we learned about hibernate many to many join table using annotations.

Happy Learning !!

Sourcecode on Github

Was this post helpful?

Join 7000+ Awesome Developers

Get the latest updates from industry, awesome resources, blog updates and much more.

* We do not spam !!

10 thoughts on “Hibernate / JPA Many to Many Mappings”

  1. Hi Lokesh,

    Some people say avoid using many-to-many as hibernate best practices. There are different explanation which are not clear to me. Is it true? Could you please explain why?

    Reply
    • Hi Ankur, I have not read any such best practice till date so please provide any relevant link discussing the M-M relationship as avoidable best practice. I believe if someone says it to avoid it then he must give any good example where this relationship is inefficient AND then what is the alternative? Just saying M-M relationship is bad, is not enough for me.

      Reply
  2. Hi,

    I have updated my project with hibernate 4 . I have tried Many to Many relationship but it is not saving in third join table.any kind of experiment in Many many relationship it giving error but does not shows what kind of error it is.It just shows error starting tomcat. need help

    Reply
  3. hi lokesh,
    I am stuck in problem related to implementing which mapping in hibernate.
    Following is my scenario:-
    I have user table and image table.
    There are 4 images where I need to store x,y coordinates of images against each user so I have created image table as
    userid,imageid,xcodnt,ycodnt.There could be no primary key in this table as imageid & userid will be multiple as:-
    1 1
    1 2
    1 3
    1 4
    2 1
    2 2
    2 3
    2 4.
    Could you please help me out this.
    Your help will be highly appreciated.
    Thanks in advance.

    Reply
  4. All you posts for hibernate mapping were really very useful for understanding . Can you please put up a post for many to many mapping with extra attributes in join table?

    Reply

Leave a Comment

HowToDoInJava

A blog about Java and related technologies, the best practices, algorithms, and interview questions.