Hibernate Many-To-Many Mapping Example Using Annotations

SHARE & COMMENT :

In this tutorial we will write a simple Java project to demonstrate Hibernate Many to Many Mapping using Java Annotations. We will first create a Java project using Maven and then will add Hibernate on it. If you have any questions, please post it in the comments section. If you are interested in receiving the future articles on Java topics, please subscribe here. If you are beginner for hibernate, please read the articles about introduction to hibernate, interceptors in hibernate and spring & hibernate integration. We also recommend good reference books for learning hibernate in our post about hibernate books.hibernate

Many To Many Relationship

A ManyToMany relationship in Java is where the source object has an attribute that stores a collection of target objects and (if) those target objects had the inverse relationship back to the source object it would also be a ManyToMany relationship.

All ManyToMany relationships require a JoinTable. The JoinTable is defined using the @JoinTable annotation and XML element. The JoinTable defines a foreign key to the source object’s primary key (joinColumns), and a foreign key to the target object’s primary key (inverseJoinColumns). Normally the primary key of the JoinTable is the combination of both foreign keys. Let’s see an example of person and phone relationship as in the below structure:

manytomany_tablestruct

Each person can have more than one phone and each phone can have more than one person assoiated with it.

Technologies Used:

Following are the tools and technologies required for this project:

  1. Java JDK 5 or above
  2. Eclipse IDE 3.2 or above
  3. Maven 3.0 or above
  4. Hibernate 3.0 or above (Hibernate Downloads)
  5. MySQL 5 above (MySql Downloads)

1.Environment Setup

Refer post Hibernate, Maven and HSQL – Example Project (XML Mapping) for environment setup (follow steps 1,2 and 3). Pass the following command in the step.1, to create a java project using Maven:

mvn archetype:generate
-DgroupId=net.javabeat.hibernate
-DartifactId=HibernateManyToManyAnnotations
-DarchetypeArtifactId=maven-archetype-quickstart
-DinteractiveMode=false

2. Adding dependencies to pom.xml

We need to add the Hibernate, MYSQL and some other dependencies to the Maven pom.xml as shown below:

 <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/maven-v4_0_0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>net.javabeat.hibernate</groupId>
   <artifactId> HibernateManyToManyAnnotations</artifactId>
   <packaging>jar</packaging>
   <version>1.0-SNAPSHOT</version>
   <name> HibernateManyToManyAnnotations</name>
   <url>http://maven.apache.org</url>
   <dependencies>
     <!-- Hibernate library dependency start -->
 		<dependency>
 			<groupId>org.hibernate</groupId>
 			<artifactId>hibernate</artifactId>
 			<version>4.1.9.Final</version>
 		</dependency>

 		<dependency>
 			<groupId>mysql</groupId>
 			<artifactId>mysql-connector-java</artifactId>
 			<version>5.1.10</version>
 		</dependency>
 		<dependency>
 			<groupId>org.hibernate</groupId>
 			<artifactId>hibernate-annotations</artifactId>
 			<version>3.3.1.GA</version>
 		</dependency>
 		<dependency>
 			<groupId>dom4j</groupId>
 			<artifactId>dom4j</artifactId>
 			<version>1.6.1</version>
 		</dependency>
 		<dependency>
 			<groupId>commons-logging</groupId>
 			<artifactId>commons-logging</artifactId>
 			<version>1.1.1</version>
 		</dependency>
 		<dependency>
 			<groupId>commons-collections</groupId>
 			<artifactId>commons-collections</artifactId>
 			<version>3.2.1</version>
 		</dependency>
 		<dependency>
 			<groupId>cglib</groupId>
 			<artifactId>cglib</artifactId>
 			<version>2.2</version>
 		</dependency>
 		<dependency>
 			<groupId>asm</groupId>
 			<artifactId>asm</artifactId>
 			<version>4.0</version>
 		</dependency>
 		<dependency>
 			<groupId>dom4j</groupId>
 			<artifactId>dom4j</artifactId>
 			<version>1.6.1</version>
 		</dependency>
 		<dependency>
 			<groupId>ehcache</groupId>
 			<artifactId>ehcache</artifactId>
 			<version>1.2.3</version>
 		</dependency>
 		<dependency>
 			<groupId>hibernate-tools</groupId>
 			<artifactId>hibernate-tools</artifactId>
 			<version>3.2.3.GA</version>
 		</dependency>
 		<dependency>
 			<groupId>jta</groupId>
 			<artifactId>jta</artifactId>
 			<version>1.1</version>
 		</dependency>
 		<dependency>
 			<groupId>log4j</groupId>
 			<artifactId>log4j</artifactId>
 			<version>1.2.11</version>
 		</dependency>
 		<dependency>
 			<groupId>oscache</groupId>
 			<artifactId>oscache</artifactId>
 			<version>2.1</version>
 		</dependency>
 		<dependency>
 			<groupId>persistence-api</groupId>
 			<artifactId>persistence-api</artifactId>
 			<version>1.0</version>
 		</dependency>
 		<!-- Hibernate library dependecy end -->
   </dependencies>
 </project>
 

As a next step, let’s execute the following command so that maven will download all the required JARs and add the same to eclipse classpath. The command line point to the directory C:\HibernateProject\ HibernateManyToManyAnnotations and execute the following command:

mvn eclipse:eclipse

3. Create Model Classes

As we should be using annotations, we need to only write the model classes:
src\main\java\net\javabeat\hibernate\Person.java and src\main\java\net\javabeat\hibernate\Phone.java.
The contents of the model classes are as below

Person.java

package net.javabeat.hibernate;

import java.io.Serializable;
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.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

/**
 * Model class for Person
 */
@Entity
@Table(name = "Person", uniqueConstraints = {
		@UniqueConstraint(columnNames = "ID"),
		@UniqueConstraint(columnNames = "NAME") })
public class Person implements Serializable {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "ID", unique = true, nullable = false)
	private Long id;

	@Column(name = "NAME")
	private String name;

	@ManyToMany(cascade = CascadeType.ALL)
	@JoinTable(name = "PERSON_PHONE",
	joinColumns = { @JoinColumn(referencedColumnName = "ID") },
	inverseJoinColumns = { @JoinColumn(referencedColumnName = "ID") })
	private Set<Phone> personPhoneNumbers = new HashSet<Phone>();

	public Person(String name, Set<Phone> personPhoneNumbers) {
		super();
		this.name = name;
		this.personPhoneNumbers = personPhoneNumbers;
	}

	public Person() {
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Set<Phone> getPersonPhoneNumbers() {
		return personPhoneNumbers;
	}

	public void setPersonPhoneNumbers(Set<Phone> personPhoneNumbers) {
		this.personPhoneNumbers = personPhoneNumbers;
	}

	public void addPhone(Phone phone) {
		this.personPhoneNumbers.add(phone);
	}

}

Phone.java

package net.javabeat.hibernate;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

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

import javax.persistence.ManyToMany;

import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

@Entity
@Table(name = "PHONE", uniqueConstraints = { @UniqueConstraint(columnNames = "ID") })
public class Phone implements Serializable {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "ID", unique = true, nullable = false)
	private Long id;

	@Column(name = "CONTACTNUMBER", unique = true, nullable = false, length = 100)
	private String contactnumber;

	@Column(name = "PHONETYPE")
	private String phonetype;

	@ManyToMany(mappedBy = "personPhoneNumbers")
	private Set<Person> persons = new HashSet<Person>();

	public Phone() {

	}

	public Phone(String contactnumber, String phonetype) {
		super();
		this.contactnumber = contactnumber;
		this.phonetype = phonetype;

	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getContactnumber() {
		return contactnumber;
	}

	public void setContactnumber(String contactnumber) {
		this.contactnumber = contactnumber;
	}

	public String getPhonetype() {
		return phonetype;
	}

	public void setPhonetype(String phonetype) {
		this.phonetype = phonetype;
	}

	public Set<Person> getPersons() {
		return persons;
	}

	public void setPersons(Set<Person> persons) {
		this.persons = persons;
	}

}

Details of the above files are as below:

  • @JoinTable annotation has been used to make the making the association between the tables PERSON and PHONE through PERSON_PHONE table as follows:
    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "PERSON_PHONE",
    joinColumns = { @JoinColumn(referencedColumnName = "ID") },
    inverseJoinColumns = { @JoinColumn(referencedColumnName = "ID") })
    private Set<Phone> personPhoneNumbers = new HashSet<Phone>();
    
  • As mentioned in the section Many to Many Relationship the JoinTable defines a foreign key to the source object’s primary key joinColumns, and a foreign key to the target object’s primary key inverseJoinColumns.
  • We then map the Phone entity to the Person entity using the mappedBy attribute in Phone.java:
    @ManyToMany(mappedBy = "personPhoneNumbers")
    private Set<Person> persons = new HashSet<Person>();
    

4. Adding Hibernate Configuration file

As a next step let’s add the hibernate.cfg.xml to the directory:/src/main/resources . Write the new file hibernate.cfg.xml in this directory. The hibernate.cfg.xml is as follows:

<?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, Connect to MYSQL -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
		<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/manisha</property>
		 <property name="connection.username">root</property>
        <property name="connection.password">root</property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>
        <property name="show_sql">true</property><property name="format_sql">true</property>

        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
        <!--create the database schema on startup if required -->
        <property name="hbm2ddl.auto">create</property>
       <mapping class="net.javabeat.hibernate.Person"></mapping>
       <mapping class="net.javabeat.hibernate.Phone"></mapping>

  </session-factory>
</hibernate-configuration>

In the above file we have set the database connection to MYSQL database . The show_sql option, if set to true will display all the executed SQL queries on the console. The property hbm2ddl.auto , if set to create, creates the schema, destroying the previous data. At the end of the file we add model classes, Person and Phone to the configuration.

Note : In case you want to use any other database then, you need to change these properties – “dialect”, “connection.driver_class”, “connection.url”, “connection.username”, and “connection.password”.

5. Create Utility class

Next, we will write a utility class to take care of Hibernate start up and retrieve the session easily. We will write the file src\main\java\net\javabeat\hibernate\HibernateUtil.java as below:

package net.javabeat.hibernate;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;

public class HibernateUtil {
	private static final SessionFactory sessionFactory;
	static {
		try {
			sessionFactory = 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;
	}
}

6. Revise the App class

Next we will revise the App.java (generated by Maven). This class tests the many-to-many relationship by creating and listing the person names and corresponding phone numbers as below:

package net.javabeat.hibernate;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;

/**
 * Main class
 *
 */
public class App {
	public static void main(String[] args) {
		System.out
		.println("Maven + Hibernate + SQL  Many to Many Using Annotations ");
		Session session = HibernateUtil.getSessionFactory().openSession();
		session.beginTransaction();
		App app = new App();

		app.savePersonInfo("Manisha");

		app.listPersonInfo();

	}

	public Long savePersonInfo(String personName) {
		Session session = HibernateUtil.getSessionFactory().openSession();
		session.beginTransaction();
		Long personId = null;
		Transaction transaction = null;
		try {
			transaction = session.beginTransaction();
			Person person = new Person();
			person.setName(personName);

			Phone ph1 = new Phone();
			Phone ph2 = new Phone();
			ph1.setContactnumber("4100000");
			ph1.setPhonetype("Landline");

			ph2.setContactnumber("988000045");
			ph2.setPhonetype("Mobile");
			person.addPhone(ph1);
			person.addPhone(ph2);
			session.save(person);

			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
		return personId;
	}

	/*
	 * Lists the person's from database table
	 */
	public void listPersonInfo() {
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction transaction = null;
		try {
			transaction = session.beginTransaction();
			@SuppressWarnings("unchecked")
			List<Person> personList = session.createQuery("FROM Person").list();

			System.out.println("List size: " + (personList).size());
			for (Iterator iterator = personList.iterator(); iterator.hasNext();) {
				Person person = (Person) iterator.next();
				Set<Phone> ph = new HashSet<Phone>();
				ph = person.getPersonPhoneNumbers();
				for (Phone p : ph) {
					System.out.println("***************************");
					System.out.println(person.getName());
					System.out.println(" Phone Type: " + p.getPhonetype());
					System.out
					.println(" Phone Number: " + p.getContactnumber());
					System.out.println("***************************");
				}
			}
			transaction.commit();
		} catch (HibernateException e) {
			transaction.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
	}

}

Here the savePersonInfo() method is used to save a new Person object and Phone object to the database.

The listPersonInfo() method is used to list name of each person in PERSON table and their corresponding phone numbers and type from PHONE table. Here we use Hibernate Query Language (HQL). The query “from Person” returns a list of all the data in the PERSON table and their corresponding phone numbers from PHONE table through PERSON_PHONE table (check the select query in the output section ). Note that in the HQL we only specify the java class names and not the table names. Later, using the for loop we iterate the list the data from Person and corresponding Phone table and hence display them on the console.

8. Final project structure

Once you have created all these source files, your project structure should look like following:
manytomany_annotation_dir_struct

9. Execution of the above code

Now let us execute the code we created above. Let’s run the App class.
Right click on App.java >Run As > Java Application.
On start of each thread, a database schema will be created and the following actions will happen.

Output on the console:
Following output is displayed on the console:

Maven + Hibernate + SQL  Many to Many Using Annotations
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.annotations.Version).
log4j:WARN Please initialize the log4j system properly.
Hibernate:
    insert
    into
        Person
        (NAME)
    values
        (?)
Hibernate:
    insert
    into
        PHONE
        (CONTACTNUMBER, PHONETYPE)
    values
        (?, ?)
Hibernate:
    insert
    into
        PHONE
        (CONTACTNUMBER, PHONETYPE)
    values
        (?, ?)
Hibernate:
    insert
    into
        PERSON_PHONE
        (persons_ID, personPhoneNumbers_ID)
    values
        (?, ?)
Hibernate:
    insert
    into
        PERSON_PHONE
        (persons_ID, personPhoneNumbers_ID)
    values
        (?, ?)
Hibernate:
    select
        person0_.ID as ID0_,
        person0_.NAME as NAME0_
    from
        Person person0_
List size: 1
Hibernate:
    select
        personphon0_.persons_ID as persons1_1_,
        personphon0_.personPhoneNumbers_ID as personPh2_1_,
        phone1_.ID as ID1_0_,
        phone1_.CONTACTNUMBER as CONTACTN2_1_0_,
        phone1_.PHONETYPE as PHONETYPE1_0_
    from
        PERSON_PHONE personphon0_
    left outer join
        PHONE phone1_
            on personphon0_.personPhoneNumbers_ID=phone1_.ID
    where
        personphon0_.persons_ID=?
***************************
Manisha
 Phone Type: Mobile
 Phone Number: 988000045
***************************
***************************
Manisha
 Phone Type: Landline
 Phone Number: 4100000
***************************

Summary

In this post we demonstrated many-to-many relation using Java annotation. We initially created a Java project using Maven, made it compatible with eclipse. Then we created model classes using annotations. We then set the values in our main class(App.java), which in turn added the values to respective tables. We also listed the data from the tables. If you are interested in receiving the future articles on Java topics, please subscribe here

Comments

comments

About Manisha Patil

Manisha S Patil, currently residing at Pune India. She is currently working as freelance writer for websites. She had earlier worked at Caritor Bangalore, TCS Bangalore and Sungard Pune. She has 5 years of experience in Java/J2EE technologies.

Comments

  1. Radek Los says:

    Hi, nice article I would like to ask how can I create relation for order items: order_item – {amount, price} – item. Where order_item is joining table with more than reference columns (for item and order) like amount and price of ordered item.

    • Can you please elaborate you query with regards to your table structure.
      If I explain in general terms the relation between Order and Items, then it would be as below:
      An order can contain a number of items, and an item can belong to a number of orders. For example, an order #123 contains item-1,item-2,item-3; in its turn, the item-1 was ordered by a few customers, and it is a part of the order #123 as well as #456. We need to achieve a many to many relationship ,hence we need a joining table order_item. Keeping this in mind you need add the following code to your Order.java POJO
      Order.java

      @ManyToMany
      @JoinTable(name = "order_item", joinColumns = { @JoinColumn(name = "order_id") }, 
      inverseJoinColumns = { @JoinColumn(name = "item_id") })
      private Set<Item> items = new HashSet<Item>();
      

      Hope this has answered your query…..

    • manishap says:

      Can you please elaborate you query with regards to your table structure.

      If I explain in general terms the relation between Order and Items, then it would be as below:
      An order can contain a number of items, and an item can belong to a
      number of orders. For example, an order #123 contains
      item-1,item-2,item-3; in its turn, the item-1 was ordered by a few
      customers, and it is a part of the order #123 as well as #456. We need
      to achieve a many to many relationship ,hence we need a joining table
      order_item. Keeping this in mind you need add the following code to your
      Order.java POJO:

      Order.java
      @ManyToMany
      @JoinTable(name = “order_item”, joinColumns = { @JoinColumn(name = “order_id”) },
      inverseJoinColumns = { @JoinColumn(name = “item_id”) })
      private Set items = new HashSet();

      Hope this has answered your query…..

    • manishap says:

      Can you please elaborate you query with regards to your table structure.

      If I explain in general terms the relation between Order and Items, then it would be as below:
      An order can contain a number of items, and an item can belong to a
      number of orders. For example, an order #123 contains
      item-1,item-2,item-3; in its turn, the item-1 was ordered by a few
      customers, and it is a part of the order #123 as well as #456. We need
      to achieve a many to many relationship ,hence we need a joining table
      order_item. Keeping this in mind you need add the following code to your
      Order.java POJO:

      Order.java
      @ManyToMany
      @JoinTable(name = “order_item”, joinColumns = { @JoinColumn(name = “order_id”) },
      inverseJoinColumns = { @JoinColumn(name = “item_id”) })
      private Set items = new HashSet();

      Hope this has answered your query!

  2. Hi,
    i’m using your code and everything works fine when i load persons entities and relative phone numbers, but when i do the contrary (loading phone numbers with associated persons) i get a looping problem… how can i solve this?
    Thanks

Speak Your Mind

*

Close
Please support the site
By clicking any of these buttons you help our site to get better