hibernate

Hibernate Many to Many Example

Many-to-Many mapping is usually implemented in the database using a Join Table. For example, we can have Cart and Item tables and Cart_Items table for many-to-many mapping. Every cart can have multiple items and every item can be part of multiple carts, so we have a many to many mapping here.

In this tutorial, we will learn about how to use Hibernate Many-To-Many Bidirectional mapping using annotation based configuration.
 
 
 
 
 

1. Introduction

Many-to-many mapping is an association between two entities where one instance of an entity is associated with the multiple instances of another entity and vice-versa. A many-to-many relationship always has two sides called an owning side and a non-owning side. The Join operation of a table is defined on the owning side and the owning side has a field that stores collection of target entities.

The many-to-many association can be either unidirectional or bidirectional.

  • In unidirectional association, only source entity has a relationship field that refers to the target entities. We can navigate this type of association from one side
  • In bi-directional association, each entity (i.e. source and target) has a relationship field that refers to each other. We can navigate this type of association from both sides

But before we move on, let’s understand the Hibernate and the Annotations.

1.1 Hibernate

  • Hibernate is an ORM (Object Relational Mapping) framework to communicate with the database using the Java API. This programming technique maps the object to the data stored in the database
  • Provides data query and retrieval facilities and is purely used for data persistence (i.e. to store or retrieve data from the database)
  • Framework internally uses the JDBC API to interact with the database and hides the internal JDBC implementations from end users

Fig. 1: Hibernate Overview
Fig. 1: Hibernate Overview

1.2 Hibernate Benefits

There are many advantages of using the Hibernate framework, for e.g.

  • Takes care of mapping Java classes to database tables using XML or annotations and without writing any line of code
  • Provides simple APIs for storing and retrieving Java objects directly to and from the database
  • Provides the facility to create the tables of the database automatically and thereby reducing manual intervention
  • If there is change in the database or in any table then we only need to change the XML properties or annotations
  • Minimize database access with smart fetching strategies as Hibernate framework internally uses the cache technique

1.3 Hibernate Annotations

  • Hibernate annotations is the newest way to define mappings without a use of an XML file
  • Developers use annotations to provide metadata configuration along with the Java code. Thus, making the code easy to understand
  • XML provides the ability to change the configuration without building the project. Thus, annotations are less powerful than XML configuration and should only be used for table and column mappings
  • Annotations are preconfigured with sensible default values, which reduce the amount of coding required. For e.g. Class name defaults to Table name and field names defaults to column names

1.4 Reference Guide on Hibernate Annotations

Hibernate Annotations are based on the JPA 2 specification. All the JPA annotations are defined in the javax.persistence.* package. The basic JPA annotations of Hibernate that can be used in an entity are the ones below.

Annotation Modifier Description
@Entity Marks a class as a Hibernate Entity (Mapped class)
@Table Name Maps this class with a database table specified by name modifier. If the name is not supplied it maps the class with a table having the same name as the class.
@Id Marks this class field as a primary key column.
@GeneratedValue Instructs database to generate a value for this field automatically.
@Column Name Maps this field with table column specified by name and uses the field name if name modifier is absent.
@ManyToMany Cascade Marks this field as the owning side of the many-to-many relationship and cascade modifier specifies which operations should cascade to the inverse side of the relationship.
mappedBy This modifier holds the field which specifies the inverse side of the relationship.
@JoinTable Name For holding this many-to-many relationship, maps this field with an intermediary database join table specified by name modifier.
joinColumns Identifies the owning side of columns which are necessary to identify a unique owning object.
inverseJoinColumns Identifies the inverse (target) side of columns which are necessary to identify a unique target object.
@JoinColumn Name Maps a join column specified by the name identifier to the relationship table specified by @JoinTable.

1.5 Download and Install Hibernate

You can read this tutorial in order to download and install Hibernate in the Eclipse IDE.

1.6 Download and Install MySQL

You can watch this video in order to download and install the MySQL database on your Windows operating system.

Now, open up the Eclipse IDE and let’s see how to implement Many-to-Many relationship in Hibernate using Annotation!

2. Hibernate Many to Many Example

2.1 Tools Used

We are using Eclipse Kepler SR2, JDK 7, MySQL database and Maven. Having said that, we have tested the code against JDK 1.8 and it works well.

2.2 Project Structure

Firstly, let’s review the final project structure, in case you are confused about where you should create the corresponding files or folder later!

Fig. 2: Hibernate Many-to-Many Mapping Application Project Structure
Fig. 2: Hibernate Many-to-Many Mapping Application Project Structure

2.3 Project Creation

This section will demonstrate on how to create a Java based Maven project with Eclipse. In Eclipse IDE, go to File -> New -> Maven Project.

Fig. 3: Create Maven Project
Fig. 3: Create Maven Project

In the New Maven Project window, it will ask you to select project location. By default, ‘Use default workspace location‘ will be selected. Select the ‘Create a simple project (skip archetype selection)‘ checkbox and just click on next button to proceed.

Fig. 4: Project Details
Fig. 4: Project Details

It will ask you to ‘Enter a group id for the artifact.’ We will input the details as shown in the below image. The version number will be by default 0.0.1-SNAPSHOT.

Fig. 5: Archetype Parameters
Fig. 5: Archetype Parameters

Click on Finish and the creation of the a maven project is completed. If you observe, it has downloaded the maven dependencies and a pom.xml file will be created. It will have the following code:

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>HibernateManyToManyMapping</groupId>
	<artifactId>HibernateManyToManyMapping</artifactId>
	<version>0.0.1-SNAPSHOT</version>
</project>

We can start adding the dependencies that developers want like Hibernate, MySQL etc. Let’s start building the application!

3. Application Building

Below are the steps involved in developing this application.

3.1 Database & Table Creation

The following MySQL script is used to create a database called tutorialDb with three tables: employee, meeting and employee_meeting (Join Table). Open MySQL terminal or workbench terminal and execute the script:

CREATE DATABASE tutorialDb;
 
USE tutorialDb;
 
CREATE TABLE employee (
	employee_id int(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 int(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 int(20) NOT NULL,
	meeting_id int(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)
);

If everything goes well, the table will be shown in the MySQL workbench. Below diagram shows the Entity relationship between these tables.

Fig. 6: Many-to-Many Bidirectional Mapping with an extra Joined Table
Fig. 6: Many-to-Many Bidirectional Mapping with an extra Joined Table

3.2 Maven Dependencies

Here, we specify only two dependencies for Hibernate Core and MySQL Connector. Rest dependencies will be auto resolved by Maven, such as Hibernate JPA and Hibernate Commons Annotations. The updated file will have the following code:

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>HibernateManyToManyMapping</groupId>
	<artifactId>HibernateManyToManyMapping</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<dependencies>
		<!-- Hibernate 4.3.6 Final -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>4.3.6.Final</version>
		</dependency>
		<!-- Mysql Connector -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.21</version>
		</dependency>
	</dependencies>
	<build>
		<finalName>${project.artifactId}</finalName>
	</build>
</project>

3.3 Java Class Creation

Let’s create the required Java files. Right click on src/main/java folder, New -> Package.

Fig. 7: Java Package Creation
Fig. 7: Java Package Creation

A new pop window will open where we will enter the package name as: com.jcg.hibernate.many2many.mapping.

Fig. 8: Java Package Name (com.jcg.hibernate.many2many.mapping)
Fig. 8: Java Package Name (com.jcg.hibernate.many2many.mapping)

Once the package is created in the application, we will need to create the model and implementation classes. Right click on the newly created package: New -> Class.

Fig. 9: Java Class Creation
Fig. 9: Java Class Creation

A new pop window will open and enter the file name as Employee. The owner entity class will be created inside the package: com.jcg.hibernate.many2many.mapping.

Fig. 10: Java Class (Employee.java)
Fig. 10: Java Class (Employee.java)

Repeat the step (i.e. Fig. 9) and enter the filename as Meeting. The mapped entity class will be created inside the package: com.jcg.hibernate.many2many.mapping.

Fig. 11: Java Class (Meeting.java)
Fig. 11: Java Class (Meeting.java)

Again, repeat the step listed in Fig. 9 and enter the file name as AppMain. The implementation class will be created inside the package: com.jcg.hibernate.many2many.mapping.

Fig. 12: Java Class (AppMain.java)
Fig. 12: Java Class (AppMain.java)

3.3.1 Implementation of Owner Entity

Owner entity is the entity which is responsible for making the association and maintaining it. In our case, I am making Employee as the owner entity. @JoinTable annotation has been used to make this association. Add the following code to it:

Employee.java

package com.jcg.hibernate.many2many.mapping;

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 meetings = new HashSet();

	public Employee() { }

	public Employee(String first_name, String last_name) {
		this.firstname = first_name;
		this.lastname = last_name;
	}

	public Long getEmployeeId() {
		return employeeId;
	}

	public void setEmployeeId(Long employee_id) {
		this.employeeId = employee_id;
	}

	public String getFirstname() {
		return firstname;
	}

	public void setFirstname(String first_name) {
		this.firstname = first_name;
	}

	public String getLastname() {
		return lastname;
	}

	public void setLastname(String last_name) {
		this.lastname = last_name;
	}

	public Set getMeetings() {
		return meetings;
	}

	public void setMeetings(Set meetings) {
		this.meetings = meetings;
	}
}

3.3.2 Implementation of Mapped Entity

Our mapped entity is Meeting which is mapped to Employee using mappedBy attribute. Add the following code to it:

Meeting.java

package com.jcg.hibernate.many2many.mapping;

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 employees = new HashSet();

	public Meeting() { }

	public Meeting(String subject) {
		this.subject = subject;
		this.meetingDate = new Date();
	}

	public Long getMeetingId() {
		return meetingId;
	}

	public void setMeetingId(Long meeting_id) {
		this.meetingId = meeting_id;
	}

	public String getSubject() {
		return subject;
	}

	public void setSubject(String subject_name) {
		this.subject = subject_name;
	}

	public Date getMeetingDate() {
		return meetingDate;
	}

	public void setMeetingDate(Date meeting_date) {
		this.meetingDate = meeting_date;
	}

	public Set getEmployees() {
		return employees;
	}

	public void setEmployees(Set employees) {
		this.employees = employees;
	}
}

3.3.3 Implementation of Utility Class

This class helps in creating the SessionFactory from the Hibernate configuration file and interacts with the database to perform the INSERT operation. Add the following code to it:

AppMain.java

 
package com.jcg.hibernate.many2many.mapping;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

public class AppMain {

	static Session sessionObj;
	static SessionFactory sessionFactoryObj;

	private static SessionFactory buildSessionFactory() {
		// Creating Configuration Instance & Passing Hibernate Configuration File
		Configuration configObj = new Configuration();
		configObj.configure("hibernate.cfg.xml");

		// Since Hibernate Version 4.x, ServiceRegistry Is Being Used
		ServiceRegistry serviceRegistryObj = new StandardServiceRegistryBuilder().applySettings(configObj.getProperties()).build(); 

		// Creating Hibernate SessionFactory Instance
		sessionFactoryObj = configObj.buildSessionFactory(serviceRegistryObj);
		return sessionFactoryObj;
	}

	public static void main(String[] args) {		
		try {
			sessionObj = buildSessionFactory().openSession();
			sessionObj.beginTransaction();

			Meeting quaterlyMeet = new Meeting("Quaterly Status Meeting");
			Meeting weeklyMeet = new Meeting("Weekly Status Meeting");
			Meeting dailyMeet  = new Meeting("Daily Status Meeting");

			Employee empObj1 = new Employee("Happy", "Potter");
			empObj1.getMeetings().add(quaterlyMeet);
			empObj1.getMeetings().add(weeklyMeet);
			sessionObj.save(empObj1);

			Employee empObj2 = new Employee("Lucifer", "Morningstar");
			empObj2.getMeetings().add(quaterlyMeet);
			sessionObj.save(empObj2);

			Employee empObj3 = new Employee("April O'", "Neil");			
			empObj3.getMeetings().add(weeklyMeet);
			empObj3.getMeetings().add(dailyMeet);
			sessionObj.save(empObj3);

			// Committing The Transactions To The Database
			sessionObj.getTransaction().commit();

			System.out.println("\n.......Records Saved Successfully To The Database.......");
		} catch(Exception sqlException) {
			if(null != sessionObj.getTransaction()) {
				System.out.println("\n.......Transaction Is Being Rolled Back.......");
				sessionObj.getTransaction().rollback();
			}
			sqlException.printStackTrace();
		} finally {
			if(sessionObj != null) {
				sessionObj.close();
			}
		}
	}
}

3.4. Hibernate Configuration File

To configure the Hibernate framework, we need to implement a configuration file i.e. hiberncate.cfg.xml. Right click on src/main/resources folder, New -> Other.

Fig. 13: XML File Creation
Fig. 13: XML File Creation

A new pop window will open and select the wizard as XML file.

Fig. 14: Wizard Selection
Fig. 14: Wizard Selection

Again, a pop-up window will open. Verify the parent folder location as HibernateManyToManyMapping/src/main/resources and enter the file name as hibernate.cfg.xml. Click Finish.

Fig. 15: hibernate.cfg.xml
Fig. 15: hibernate.cfg.xml

Once the file is created, we will include the database configuration. Add the following code to it:

hibernate.cfg.xml

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
	<session-factory>
		<!-- SQL Dialect -->
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

		<!-- Database Connection Settings -->
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/tutorialDb</property>
		<property name="hibernate.connection.username">root</property>
		<property name="hibernate.connection.password"></property>
		<property name="show_sql">true</property>

		<!-- Specifying Session Context -->
		<property name="hibernate.current_session_context_class">org.hibernate.context.internal.ThreadLocalSessionContext</property>

		<!-- Mapping With Model Class Containing Annotations -->
		<mapping class="com.jcg.hibernate.many2many.mapping.Employee" />
		<mapping class="com.jcg.hibernate.many2many.mapping.Meeting" />
	</session-factory>
</hibernate-configuration>

Notes:

  • Here, we instructed Hibernate to connect to a MySQL database named tutorialDb and the Mapping classes to be loaded
  • We have also instructed Hibernate framework to use MySQLDialect i.e. Hibernate will optimize the generated SQL statements for MySQL
  • This configuration will be used to create a Hibernate SessionFactory object

4. Run the Application

To run the Hibernate application, Right click on the AppMain class, Run As -> Java Application.

Fig. 16: Run Application
Fig. 16: Run Application

5. Project Demo

On executing the AppMain class, you will see the records in employee, meeting, and employee_meeting tables. Developers can debug the example and see what happens in the database after every step. Enjoy!

Fig. 17: Application Output
Fig. 17: Application Output

Below is the snapshot of MySQL Database after execution of the above program.

Employee Table

Fig. 18: Employee Table Records
Fig. 18: Employee Table Records

Meeting Table

Fig. 19: Meeting Table Records
Fig. 19: Meeting Table Records

Employee Meeting Table

Fig. 20: Employee Meeting Table Records
Fig. 20: Employee Meeting Table Records

That’s all for this post. Happy Learning!!

6. Conclusion

In Many-To-Many association, an extra table is used (known as Joined table) whose primary key is the combination of the primary key of both the associated tables. In other words, there is a foreign key association between the joined table and the associated tables. That’s all for Hibernate Many-To-Many mapping example tutorial and I hope this article served you whatever you were looking for.

7. Download the Eclipse Project

This was an example of Hibernate Many-To-Many Mapping.

Download
You can download the full source code of this example here: Hibernate Many2Many Mapping Example

Yatin

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button