≡ Menu

Hibernate @ManyToMany Unidirectional and Bidirectional

Hibernate @ManyToMany Unidirectional

The Many-to-Many relationship can be best described by example.

The example we’re going to use is that of the relationship between an Author and a Book.

Authors publish Books, and Books have Authors. Any one Author can publish many Books, and any one Book can be published by many Authors, so this is why it is a many to many relationship.

Other examples of the many to many relationship are Students to Courses and Employees to Projects.

Let’s take a look at how the unidirectional many-to-many relationship is created using Hibernate:

Author.java

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Author
{
  private Long authorId;
  private String authorName;
	
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  public Long getAuthorId()
	{
		return authorId;
	}
	public void setAuthorId(Long authorId)
	{
		this.authorId = authorId;
	}
	
	@Column(name="author_name")
	public String getAuthorName()
	{
		return authorName;
	}
	public void setAuthorName(String authorName)
	{
		this.authorName = authorName;
	}
}

Book.java

import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;

@Entity
public class Book
{
  private Long bookId;
  private String bookName;
  private Set<Author> authors;
  
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  public Long getBookId()
	{
		return bookId;
	}
	public void setBookId(Long bookId)
	{
		this.bookId = bookId;
	}
	
	@Column(name="book_name")
	public String getBookName()
	{
		return bookName;
	}
	public void setBookName(String bookName)
	{
		this.bookName = bookName;
	}
	@ManyToMany(cascade=CascadeType.ALL)
	@JoinTable(name="author_book", joinColumns=@JoinColumn(name="book_id"), inverseJoinColumns=@JoinColumn(name="author_id"))
	public Set<Author> getAuthors()
	{
		return authors;
	}
	public void setAuthors(Set<Author> authors)
	{
		this.authors = authors;
	}
}

The only thing that’s different from the other relationships we’ve already looked at in the past two posts is the use of the join table. A join table is necessary to facilitate the many-to-many relationship. Since we need to use this 3rd table in the database schema to map out this many to many relationship, we’ll need to let Hibernate know how to construct this join table.

We first specify the name of the table “author_book”. The convention for naming the join table is to concatenate the two names of the tables that make up the relationship, hence “author_book”. The next thing we must do is specify the names of the foreign keys that will exist inside the table. These foreign keys are referred to as the join column and inverse join column. The join column in this case refers to the name of the foreign key that belongs to the object that we’re currently coding… which in this case is the Book object. So that’s why we specify “book_id” as the join column. The inverse join column is just the name of the foreign key that belongs to the OTHER table, which is the Author table, hence “author_id”.

With that code in place, we’ve now successfully mapped out our relationship! All that’s left is to understand how to create the objects and assign the appropriate values to them.

Code to Persist Data

Set<Author> howToProgramWithJavaAuthor = new HashSet<Author>();
		Set<Author> howToProgramWithJava2ndAuthors = new HashSet<Author>();
		Set<Author> howToPlayGuitarAuthor = new HashSet<Author>();
		
		Author author = new Author();
		author.setAuthorName("Trevor Page");
		howToProgramWithJavaAuthor.add(author);
		
		Author author2 = new Author();
		author2.setAuthorName("John Doe");
		
		howToProgramWithJava2ndAuthors.add(author);
		howToProgramWithJava2ndAuthors.add(author2);
		howToPlayGuitarAuthor.add(author2);
		
		Book book = new Book();
		book.setBookName("How to Program with Java");
		
		Book book2 = new Book();
		book2.setBookName("How to Program with Java 2nd Edition");
		
		Book book3 = new Book();
		book3.setBookName("How to Play Guitar");
		
		book.setAuthors(howToProgramWithJavaAuthor);
		book2.setAuthors(howToProgramWithJava2ndAuthors);
		book3.setAuthors(howToPlayGuitarAuthor);
		
		dao.save(book);
		dao.save(book2);
		dao.save(book3);

In the unidirectional relationship (just like with the other two types of relationships), we set the parent values into the children. So in this case we set the Authors into the Book objects. Make sure you don’t forget that we need to assign a Set of Authors into the Book objects.

We then save each Book object via our standard DAO object and we’re all set!

Hibernate @ManyToMany Bidirectional

Author.java

import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;

@Entity
public class Author
{
  private Long authorId;
  private String authorName;
	private Set<Book> books;
  
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  @Column(name="author_id")
  public Long getAuthorId()
	{
		return authorId;
	}
	public void setAuthorId(Long authorId)
	{
		this.authorId = authorId;
	}
	
	@Column(name="author_name")
	public String getAuthorName()
	{
		return authorName;
	}
	public void setAuthorName(String authorName)
	{
		this.authorName = authorName;
	}
	
	@ManyToMany(cascade=CascadeType.ALL, mappedBy="authors")
	public Set<Book> getBooks()
	{
		return books;
	}
	public void setBooks(Set<Book> books)
	{
		this.books = books;
	}
}

The main difference between the bidirectional and unidirectional many to many relationship is the fact that we need to create the instance variable that will hold references to Books in the Author object. This makes sense since we’re creating the bidirectional many to many relationship, which means we should be able to access the objects that are related to both the Books and Authors from either object.

Knowing this, we assign a Set of Books to the Author object.

On the getter method, we create the @ManyToMany mapping with the key mappedBy property to indicate that this is the parent side of the relationship (the owning side).

This is the case because we can have an Author without a Book object (I decided that an Author can be in the process of writing a book, but hasn’t yet published it, so an Author can exist without a Book).

Book.java

import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;

@Entity
public class Book
{
  private Long bookId;
  private String bookName;
  private Set<Author> authors;
  
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  @Column(name="book_id")
  public Long getBookId()
	{
		return bookId;
	}
	public void setBookId(Long bookId)
	{
		this.bookId = bookId;
	}
	
	@Column(name="book_name")
	public String getBookName()
	{
		return bookName;
	}
	public void setBookName(String bookName)
	{
		this.bookName = bookName;
	}
	@ManyToMany(cascade=CascadeType.ALL)
	@JoinTable(name="author_book", joinColumns=@JoinColumn(name="book_id"), inverseJoinColumns=@JoinColumn(name="author_id"))
	public Set<Author> getAuthors()
	{
		return authors;
	}
	public void setAuthors(Set<Author> authors)
	{
		this.authors = authors;
	}
}

The Book class remains the same as in the unidirectional code above.

But the way we persist the objects will change:

Code to Persist Data

Set<Author> howToProgramWithJavaAuthor = new HashSet<Author>();
		Set<Author> howToProgramWithJava2ndAuthors = new HashSet<Author>();
		Set<Author> howToPlayGuitarAuthor = new HashSet<Author>();
		
		Set<Book> trevorsBooks = new HashSet<Book>();
		Set<Book> johnsBooks = new HashSet<Book>();
		
		Author author = new Author();
		author.setAuthorName("Trevor Page");
		howToProgramWithJavaAuthor.add(author);
		
		Author author2 = new Author();
		author2.setAuthorName("John Doe");
		
		howToProgramWithJava2ndAuthors.add(author);
		howToProgramWithJava2ndAuthors.add(author2);
		howToPlayGuitarAuthor.add(author2);
		
		Book book = new Book();
		book.setBookName("How to Program with Java");
		
		Book book2 = new Book();
		book2.setBookName("How to Program with Java 2nd Edition");
		
		Book book3 = new Book();
		book3.setBookName("How to Play Guitar");
		
		trevorsBooks.add(book);
		trevorsBooks.add(book2);
		johnsBooks.add(book2);
		johnsBooks.add(book3);
		author.setBooks(trevorsBooks);
		author2.setBooks(johnsBooks);
		book.setAuthors(howToProgramWithJavaAuthor);
		book2.setAuthors(howToProgramWithJava2ndAuthors);
		book3.setAuthors(howToPlayGuitarAuthor);
		
		dao.save(author);
		dao.save(author2);

This looks like a big jumble of code, but the only thing we’ve done is add the code to assign the other half of the relationship. This means that we need to now create Sets that represent the books. We assign the appropriate Books into these new Sets and assign them to the Authors.

Now the only difference is that we save the Authors, as that’s how it’s done with the bidirectional relationships… the unidirectional relationships require that you save the child side via DAOs.

If you enjoyed this, check a few other popular posts:

Sorting Collections

Exceptions in Java

Hibernate Persistence For Beginners 

{ 13 comments… add one }

  • Srividya August 25, 2014, 10:16 am

    Hey Hi Trevor!!!!! I have been listening and just following your podcasts and website from an year. You are just awesome. The way you try to deliver the concepts and make them understand is fabulous. You are real Java Guru to me!!! LAST BUT NOT THE LEAST Sir can you please upload a couple of podcasts on the CONCEPTS OF OPERATING SYSTEMS and the main conepts to be known in OS which will help me out in my academics. Hoping to listen to that podcast asap. Thank you sir 🙂

    • Trevor Page August 25, 2014, 2:58 pm

      Thanks for the comment, glad to hear that I’m helping you out, I love to hear that kind of feedback.

      To address your request for a podcast topic, I’ll need a bit more details from you. What exactly do you mean by the concepts of operating systems? What are the top three questions you’d have on this subject that you’d like me to answer?

      • Srividya August 26, 2014, 12:10 pm

        Hey Trevor its very glad to hear from you. Actually I will be attending my campus interviews in a month or so. So podcast relating to the general and basic interview questions that will be asked on Operating Systems and also the concepts of bit architecture, semaphores and scheduling algorithms are the things I am a bit confused on. So please help me out in these areas. Thank you once again for your immediate response 🙂

        • Trevor Page August 30, 2014, 9:32 am

          Unfortunately I have no experience in any of those topics, so I don’t think I can be of assistance there.

  • Reej February 11, 2015, 4:40 am

    The sample was very well explained. I have a design where there exists a user table and role table. when a user is assigned a role, i need to create a mapping table. how can we achieve this. the mapping table should have user id and role id. it should be actually a many to many. Both the user and roles will be already there, I need a mapping table when a user is assigned to role. Thanks in advance for the help.

  • Kedar April 7, 2015, 2:31 am

    Very good explanation of many to many. But I observe here that keeping both side collections in sync is controlled in the client program (Persistence program). If this part forgets to update both side collections, it will make data inconsistent. If we try to encapsulate these 2 parts in one method as a unit (for updates from both sides), it creates a problem – a possibility of endless loop. Authors of UML book suggest an Association class to map any many to many relationship. What do you recommend? Your use of external collections is it an implementation of association class?

  • Anadi Mishra August 10, 2015, 2:50 am

    Going by the JavaDocs for this annotation; “Every many-to-many association has two sides, the owning side and the non-owning, or inverse, side. The join table is specified on the owning side. If the association is bidirectional, either side may be designated as the owning side. If the relationship is bidirectional, the non-owning side must use the mappedBy element of the ManyToMany annotation to specify the relationship field or property of the owning side.”

    Going by the Book is the owning side (Parent) here and Author non-owning (child)?

  • antonio August 12, 2016, 11:29 am

    Great explanation Trevor! How Can I manage a many to many relation for a 3rd table with relations attributes?
    I’m learning both JPA building a project with an Employee and Project table to relate with a 3rd table as many to many relationship with relationship attributes…enities for both 3 tables have to be created?can you get us an example please?

  • WhiteBear September 5, 2016, 4:05 am

    Hi Trevor, I’m a beginner in SpringMVC + Hibernate. Can i ask you that Do i must have these tables in database mysql, i must be mapping annotation by code java or this code java can auto generate these tables in database?

    Thanks for listening, my sir.

  • Rabi August 19, 2017, 5:29 am

    Great Article….nicely explained…
    It clears all the concept regarding to mapping in hibernate…
    really enjoyed….

  • Pranav Kuldharan February 8, 2018, 7:51 am

    Great Article….nicely explained…

  • mayur April 27, 2018, 5:51 am

    I have tried same as you done in my project i am getting compatability issue

  • Rishabh October 31, 2018, 5:12 am

    I have used unidirectional manytomany relationship, Now i want to delete a mapping from author_book table. How can i delete that mapping. As author_book is not a model.

Leave a Comment