Hibernate Many To Many Annotation Mapping Tutorial

Welcome to the Hibernate Tutorial Series. In previous tutorial we saw how to implement Many to Many relationship using XML mapping. In this tutorial we will modify the source code from previous Many To Many XML mapping tutorial and add JPA/Annotation support to it.

Let us see how to implement Many-to-Many relationship in Hibernate using Annotation.

1. Create Database

For this example, we will MySQL database. We are using Employee-Meeting relationship as a many to many relationship example. Each Employee can attain more than one meetings and each meetings can have more than one employee.

CREATE TABLE `employee` ( `employee_id` BIGINT(10) NOT NULL AUTO_INCREMENT, `firstname` VARCHAR(50) NULL DEFAULT NULL, `lastname` VARCHAR(50) NULL DEFAULT NULL, PRIMARY KEY (`employee_id`) ) CREATE TABLE `meeting` ( `meeting_id` BIGINT(20) NOT NULL AUTO_INCREMENT, `subject` VARCHAR(50) NOT NULL, `meeting_date` DATE NOT NULL, PRIMARY KEY (`meeting_id`) ) CREATE TABLE `employee_meeting` ( `employee_id` BIGINT(20) NOT NULL, `meeting_id` BIGINT(20) NOT NULL, PRIMARY KEY (`employee_id`, `meeting_id`), INDEX `FK_MEETING` (`meeting_id`), CONSTRAINT `FK_EMPLOYEE` FOREIGN KEY (`employee_id`) REFERENCES `employee` (`employee_id`), CONSTRAINT `FK_MEETING` FOREIGN KEY (`meeting_id`) REFERENCES `meeting` (`meeting_id`) )
Code language: SQL (Structured Query Language) (sql)

2. Project Setup

Download the source code: Hibernate-many-to-many-set-xml.zip (9 KB) and import the project in Eclipse. We will update the source code.

3. Update Maven Dependency

File: pom.xml

<?xml version="1.0" encoding="UTF-8"?><project> <modelVersion>4.0.0</modelVersion> <groupId>HibernateCache</groupId> <artifactId>HibernateCache</artifactId> <version>0.0.1-SNAPSHOT</version> <description></description> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>ejb3-persistence</artifactId> <version>1.0.1.GA</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>3.3.1.GA</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.10</version> </dependency> </dependencies> </project>
Code language: HTML, XML (xml)

3. Remove Hibernate Mapping (hbm) Files

We are not going to use hibernate mapping files or hbm files as we will map the model using Java 5 Annotations. Delete the files employee.hbm.xml and meeting.hbm.xml.

4. Update Hibernate Model Class

We will update Employee and Meeting model classes and add Annotations to map them with database table.

File: Employee.java

package net.viralpatel.hibernate; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.Table; @Entity @Table(name="EMPLOYEE") public class Employee { @Id @Column(name="EMPLOYEE_ID") @GeneratedValue private Long employeeId; @Column(name="FIRSTNAME") private String firstname; @Column(name="LASTNAME") private String lastname; @ManyToMany(cascade = {CascadeType.ALL}) @JoinTable(name="EMPLOYEE_MEETING", joinColumns={@JoinColumn(name="EMPLOYEE_ID")}, inverseJoinColumns={@JoinColumn(name="MEETING_ID")}) private Set<Meeting> meetings = new HashSet<Meeting>(); public Employee() { } public Employee(String firstname, String lastname) { this.firstname = firstname; this.lastname = lastname; } // Getter and Setter methods }
Code language: Java (java)

File: Meeting.java

package net.viralpatel.hibernate; import java.util.Date; import java.util.HashSet; import java.util.Set; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.ManyToMany; import javax.persistence.Table; @Entity @Table(name="MEETING") public class Meeting { @Id @Column(name="MEETING_ID") @GeneratedValue private Long meetingId; @Column(name="SUBJECT") private String subject; @Column(name="MEETING_DATE") private Date meetingDate; @ManyToMany(mappedBy="meetings") private Set<Employee> employees = new HashSet<Employee>(); public Meeting(String subject) { this.subject = subject; this.meetingDate = new Date(); } // Getter and Setter methods }
Code language: Java (java)

Let us understand the annotations we used here to map Many to many relationship.

@ManyToMany – Is used to create many-to-many relationship between Employee and Meeting entities. If the Collection is defined using generics to specify the element type, the associated target entity class does not need to be specified; otherwise it must be specified. 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.

Note that in above entity classes, Employee is defined as relationship owner as @JoinColumn is define in Employee class and mappedBy is specified in Meeting class.

@JoinTable – Is used to define the join table (link table) for many-to-many relationship. It is specified on the owning side of a many-to-many association, or in a unidirectional one-to-many association. In this case the join table is EMPLOYEE_MEETING.

If the JoinTable annotation is missing, the default values of the annotation elements apply. The name of the join table is assumed to be the table names of the associated primary tables concatenated together (owning side first) using an underscore.

@JoinColumn – Is used to define the join column (linking column) in both main tables.

Note that we have used SET to map meetings with employee and vice versa. A <set> is similar to except that it can only store unique objects. That means no duplicate elements can be contained in a set. When you add the same element to a set for second time, it will replace the old one. A set is unordered by default but we can ask it to be sorted. The corresponding type of a <set> in Java is java.util.Set.

5. Hibernate Utility Class

In previous example, the Hibernate Utility class uses Hibernate’s org.hibernate.cfg.Configuration class to generate SessionFactory. For this example we will replace this class with org.hibernate.cfg.AnnotationConfiguration class. Following is the code for HibernateUtil.java class.

File: HibernateUtil.java

package net.viralpatel.hibernate; import org.hibernate.SessionFactory; import org.hibernate.cfg.AnnotationConfiguration; public class HibernateUtil { private static final SessionFactory sessionFactory = buildSessionFactory(); private static SessionFactory buildSessionFactory() { try { // Create the SessionFactory from hibernate.cfg.xml return new AnnotationConfiguration().configure() .buildSessionFactory(); } catch (Throwable ex) { System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } }
Code language: Java (java)

6. Hibernate Configuration File

Edit Hibernate configuration file (hibernate.cfg.xml) and add mappings for Employee and Meeting classes. Following is the final hibernate.cfg.xml file:

File: hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- Database connection settings --> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost:3306/tutorial</property> <property name="connection.username">root</property> <property name="connection.password"></property> <property name="connection.pool_size">1</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <property name="current_session_context_class">thread</property> <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> <property name="show_sql">true</property> <property name="hbm2ddl.auto">validate</property> <mapping class="net.viralpatel.hibernate.Employee"/> <mapping class="net.viralpatel.hibernate.Meeting"/> </session-factory> </hibernate-configuration>
Code language: HTML, XML (xml)

7. Review Project Structure

Execute example

Execute following Main class to test Many-to-many relational mapping using Annotation.

File: Main.java

package net.viralpatel.hibernate; import org.hibernate.Session; import org.hibernate.SessionFactory; public class Main { public static void main(String[] args) { SessionFactory sf = HibernateUtil.getSessionFactory(); Session session = sf.openSession(); session.beginTransaction(); Meeting meeting1 = new Meeting("Quaterly Sales meeting"); Meeting meeting2 = new Meeting("Weekly Status meeting"); Employee employee1 = new Employee("Sergey", "Brin"); Employee employee2 = new Employee("Larry", "Page"); employee1.getMeetings().add(meeting1); employee1.getMeetings().add(meeting2); employee2.getMeetings().add(meeting1); session.save(employee1); session.save(employee2); session.getTransaction().commit(); session.close(); } }
Code language: Java (java)

Output:

Hibernate: insert into EMPLOYEE (firstname, lastname) values (?, ?) Hibernate: insert into MEETING (SUBJECT, MEETING_DATE) values (?, ?) Hibernate: insert into MEETING (SUBJECT, MEETING_DATE) values (?, ?) Hibernate: insert into EMPLOYEE (firstname, lastname) values (?, ?) Hibernate: insert into EMPLOYEE_MEETING (EMPLOYEE_ID, MEETING_ID) values (?, ?) Hibernate: insert into EMPLOYEE_MEETING (EMPLOYEE_ID, MEETING_ID) values (?, ?) Hibernate: insert into EMPLOYEE_MEETING (EMPLOYEE_ID, MEETING_ID) values (?, ?)
Code language: SQL (Structured Query Language) (sql)

Download Source Code

Hibernate-many-to-many-annotation.zip (8 KB)

View Comments

  • Hi , Can any body give me an example for fetching the data of both tables using Join table?
    How to write the Query?

    Thanks in advance,
    Chandu Sannamuri

  • Great article. I had one question though. In my EMPLOYEE_MEETING table I have few other attributes. How do I handle these attributes? These are the columns

    EmployeeId
    MeetingId
    EmployeeResponse

  • Hi,

    When i update the employee_meeting table from employee side, it just replace the old value with the same employee_id and enter the new one. So, is this the behavior of many to many or i did something wrong.

  • Hi,
    I like your tutorial. can you please extend the tutorial with many to many with extra columns. thanks in advance.

  • Hi all i am also use same procedure in my project. but problem is when i want to insert the data in mapping table for same employee,hibernate 1st delete the exiting relation for same employee then insert the new mapping.means 1st hibernate run the delete query for exit customer then insert mapping employee id and meeting i..

    Please anyone help me.

  • Thanks for this best tutorial
    it works fine but when i try to update row (session.update) it give me this exception
    Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1

  • thanks for this tutorial!! but would you please transform this tutorial to a web based application? Thanks!!

Recent Posts

  • Java

Java URL Encoder/Decoder Example

Java URL Encoder/Decoder Example - In this tutorial we will see how to URL encode/decode…

5 years ago
  • General

How to Show Multiple Examples in OpenAPI Spec

Show Multiple Examples in OpenAPI - OpenAPI (aka Swagger) Specifications has become a defecto standard…

5 years ago
  • General

How to Run Local WordPress using Docker

Local WordPress using Docker - Running a local WordPress development environment is crucial for testing…

5 years ago
  • Java

Create and Validate JWT Token in Java using JJWT

1. JWT Token Overview JSON Web Token (JWT) is an open standard defines a compact…

5 years ago
  • Spring Boot

Spring Boot GraphQL Subscription Realtime API

GraphQL Subscription provides a great way of building real-time API. In this tutorial we will…

5 years ago
  • Spring Boot

Spring Boot DynamoDB Integration Test using Testcontainers

1. Overview Spring Boot Webflux DynamoDB Integration tests - In this tutorial we will see…

5 years ago