Hibernate – Many-to-Many example (XML Mapping)

Many-to-many relationships occur when each record in an entity may have many linked records in another entity and vice-versa.

In this tutorial, we show you how to work with many-to-many table relationship in Hibernate, via XML mapping file (hbm).

Note
For many to many with extra columns in join table, please refer to this tutorial.

Tools and technologies used in this tutorials :

  1. Hibernate 3.6.3.Final
  2. MySQL 5.1.15
  3. Maven 3.0.3
  4. Eclipse 3.6

Project Structure

Project structure of this tutorial.

many to many project folder

Project Dependency

Get latest hibernate.jar from JBoss repository.

File : pom.xml


<project ...>
 
	<repositories>
		<repository>
			<id>JBoss repository</id>
			<url>http://repository.jboss.org/nexus/content/groups/public/</url>
		</repository>
	</repositories>
 
	<dependencies>
 
		<!-- MySQL database driver -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.15</version>
		</dependency>
 
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>3.6.3.Final</version>
		</dependency>
 
		<dependency>
			<groupId>javassist</groupId>
			<artifactId>javassist</artifactId>
			<version>3.12.1.GA</version>
		</dependency>
 
	</dependencies>
</project>

1. “Many-to-many” example

This is a many-to-many relationship table design, a STOCK table has more than one CATEGORY, and CATEGORY can belong to more than one STOCK, the relationship is linked with a third table called STOCK_CATEGORY.

Table STOCK_CATEGORY only consist of two primary keys, and also foreign key reference back to STOCK and CATEGORY.

many to many ER diagram

MySQL table scripts


CREATE TABLE `stock` (
  `STOCK_ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `STOCK_CODE` varchar(10) NOT NULL,
  `STOCK_NAME` varchar(20) NOT NULL,
  PRIMARY KEY (`STOCK_ID`) USING BTREE,
  UNIQUE KEY `UNI_STOCK_NAME` (`STOCK_NAME`),
  UNIQUE KEY `UNI_STOCK_ID` (`STOCK_CODE`) USING BTREE
)

CREATE TABLE `category` (
  `CATEGORY_ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `NAME` varchar(10) NOT NULL,
  `DESC` varchar(255) NOT NULL,
  PRIMARY KEY (`CATEGORY_ID`) USING BTREE
)

CREATE TABLE  `stock_category` (
  `STOCK_ID` int(10) unsigned NOT NULL,
  `CATEGORY_ID` int(10) unsigned NOT NULL,
  PRIMARY KEY (`STOCK_ID`,`CATEGORY_ID`),
  CONSTRAINT `FK_CATEGORY_ID` FOREIGN KEY (`CATEGORY_ID`) REFERENCES `category` (`CATEGORY_ID`),
  CONSTRAINT `FK_STOCK_ID` FOREIGN KEY (`STOCK_ID`) REFERENCES `stock` (`STOCK_ID`)
)

2. Hibernate Model Class

Create two model classes – Stock.java and Category.java, to represent the above tables. No need to create an extra class for table ‘stock_category‘.

File : Stock.java


package com.mkyong.stock;

import java.util.HashSet;
import java.util.Set;

public class Stock implements java.io.Serializable {

	private Integer stockId;
	private String stockCode;
	private String stockName;
	private Set<Category> categories = new HashSet<Category>(0);

	//getter, setter and constructor
}

File : Category.java


package com.mkyong.stock;

import java.util.HashSet;
import java.util.Set;

public class Category implements java.io.Serializable {

	private Integer categoryId;
	private String name;
	private String desc;
	private Set<Stock> stocks = new HashSet<Stock>(0);

	//getter, setter and constructor
}

3. Hibernate XML Mapping

Now, create two Hibernate mapping files (hbm) – Stock.hbm.xml and Category.hbm.xml. You will noticed the third ‘stock_category‘ table is reference via “many-to-many” tag.

File : Stock.hbm.xml


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.mkyong.stock.Stock" table="stock" catalog="mkyongdb">
        <id name="stockId" type="java.lang.Integer">
            <column name="STOCK_ID" />
            <generator class="identity" />
        </id>
        <property name="stockCode" type="string">
            <column name="STOCK_CODE" length="10" not-null="true" unique="true" />
        </property>
        <property name="stockName" type="string">
            <column name="STOCK_NAME" length="20" not-null="true" unique="true" />
        </property>
        <set name="categories" table="stock_category" 
        	inverse="false" lazy="true" fetch="select" cascade="all" >
            <key>
                <column name="STOCK_ID" not-null="true" />
            </key>
            <many-to-many entity-name="com.mkyong.stock.Category">
                <column name="CATEGORY_ID" not-null="true" />
            </many-to-many>
        </set>
    </class>
</hibernate-mapping>

File : Category.hbm.xml


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.mkyong.stock.Category" table="category" catalog="mkyongdb">
        <id name="categoryId" type="java.lang.Integer">
            <column name="CATEGORY_ID" />
            <generator class="identity" />
        </id>
        <property name="name" type="string">
            <column name="NAME" length="10" not-null="true" />
        </property>
        <property name="desc" type="string">
            <column name="[DESC]" not-null="true" />
        </property>
        <set name="stocks" table="stock_category" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="CATEGORY_ID" not-null="true" />
            </key>
            <many-to-many entity-name="com.mkyong.stock.Stock">
                <column name="STOCK_ID" not-null="true" />
            </many-to-many>
        </set>
    </class>
</hibernate-mapping>

4. Hibernate Configuration File

Now, puts Stock.hbm.xml and Category.hbm.xml and MySQL detail in hibernate.cfg.xml.

File : 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>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mkyongdb</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">password</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="show_sql">true</property>
    <property name="format_sql">true</property>
    <mapping resource="com/mkyong/stock/Stock.hbm.xml" />
    <mapping resource="com/mkyong/stock/Category.hbm.xml" />
</session-factory>
</hibernate-configuration>

5. Run It

Run it, Hibernate will insert a record into the STOCK table, two records into the CATEGORY table, and also two records into the STOCK)CATEGORY table.

File : App.java


package com.mkyong;

import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import com.mkyong.stock.Category;
import com.mkyong.stock.Stock;
import com.mkyong.util.HibernateUtil;

public class App {
	public static void main(String[] args) {
		
        System.out.println("Hibernate many to many (XML Mapping)");
	Session session = HibernateUtil.getSessionFactory().openSession();

	session.beginTransaction();

	Stock stock = new Stock();
        stock.setStockCode("7052");
        stock.setStockName("PADINI");
 
        Category category1 = new Category("CONSUMER", "CONSUMER COMPANY");
        Category category2 = new Category("INVESTMENT", "INVESTMENT COMPANY");
    
        Set<Category> categories = new HashSet<Category>();
        categories.add(category1);
        categories.add(category2);
        
        stock.setCategories(categories);
        
        session.save(stock);
    
	session.getTransaction().commit();
	System.out.println("Done");
	}
}

Output …result should be self-explanatory


Hibernate many to many (XML Mapping)
Hibernate: 
    insert 
    into
        mkyongdb.stock
        (STOCK_CODE, STOCK_NAME) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        mkyongdb.category
        (NAME, `DESC`) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        mkyongdb.category
        (NAME, `DESC`) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        stock_category
        (STOCK_ID, CATEGORY_ID) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        stock_category
        (STOCK_ID, CATEGORY_ID) 
    values
        (?, ?)
Done
Hibernate Annotation
For many-to-many in Hibernate annotation, please refer to this example.

Reference

  1. Hibernate Documentation – many to many relationship.

About the Author

author image
mkyong
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter, or befriend him on Facebook or Google Plus. If you like my tutorials, consider make a donation to these charities.

Comments

Leave a Reply

avatar
newest oldest most voted
Nandu K
Guest
Nandu K

for those who are getting ora-01747 error,
change column name from desc to something else as DESC is a reserved key word.
make changes accordingly in the hdm file too.

Jishnu
Guest
Jishnu

Thank you, Nandu.
you saved my life :D

Jyothi thomas
Guest
Jyothi thomas

: thanks

Binh Thanh Nguyen
Guest
Binh Thanh Nguyen

Thanks, nice post

Ashish Mishra
Guest
Ashish Mishra

Nice examle. I have one doubt here. If I want to insert the data into stock_category table how to do it?

facilus
Guest
facilus

Hey,

In my composite table i’ve another fields :

1- Composite primary key like this example (id_table1, id_table2)
2- a foreign key with table3 (id_table3)
3- a column with Int value (quantity)

Questions :

1- How to map this model in “hbm file” and in java ?
2- How to use criteria for obteining list with key = id_table_1 ?

Alessandra P.
Guest
Alessandra P.

I am using Oracle DB so I have to use a sequence ( ) instead of your because Oracle DB doesn’t support identity key generator.

The problem is that a sequence generates an id even when it is already assigned to a table row. What should I use instead?

gaurav shirbhate
Guest
gaurav shirbhate

I have to inject Repository class in Converter class which implements converter interface for accessing all the data from database, but i am not getting how to inject repository class in converter class

gaurav shirbhate
Guest
gaurav shirbhate

please tell me how to inject repository class in converter class

Mitch
Guest
Mitch

As always, these examples are very helpful. Thanks!

Mitch

Ing
Guest
Ing

In this case, Stock is the owner of the relationship. What are the changes to be made to make Category as owner?

Keith
Guest
Keith

I know this is old, but just to say; I don’t know what this sunil is on about.

I have just found this example, used it to replace my (incorrect) implementation os a many-to-many relationship and it’s worked first time!!!!

Another quality and easy to understand example from MkYong!

IMO, the best site for coding examples, on the Net!

Sathish
Guest
Sathish

Dear Sir,

Sir,while i’m using cascade=”save” to perform insertion operations in relationships,i’m getting an exception like “Unsupported cascading style:save”….what the problem would be???????? please help me out this….

tunnaruto
Guest
tunnaruto

after following rhis tutorial, when i run an HQL query “from Stock” i got the following exception:
org.hibernate.MappingException: An association from the table stock_category refers to an unmapped class: pojosMkyong.Category
at org.hibernate.cfg.Configuration.secondPassCompileForeignKeys(Configuration.java:1252)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1170)
at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:324)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1286)
at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:859)

why?

michael
Guest
michael

I follow this tutorial from start to end but the database populates the stock and stock category table and not three tables. Why like this?

Thanks

Feri
Guest
Feri

Dear Michael,
The solution to your problem could be the following: Just try to set the following property (inverse) from this line to false in both hbm files:

 
<set name="stocks" table="stock_category" inverse="true" lazy="true" fetch="select">

This will ensure that the insertion will work properly in all 3 tables

aminos
Guest
aminos

Hey thanks for the tutorial can u make the same example but with extra columns the stock_category table ,i need it with xml not annotation please help me

Pramod
Guest
Pramod
how to i use struts with hibernate for the above example where i need to have more than 1 actionform bean. So that the data can b collected for different table and inserted on the go. Example: I have a employeedtls table ,addrstable,logindtls table where employee is the master table whenever a new employee joins the house his details need to be inserted in to 3 tables first in logindtls and get primary key then from addrsdtls and get the primary key at last we need to insert the collected primary keys into employeedtls as a foreign key and that… Read more »
Quang
Guest
Quang

Thanks for sharing useful article. I don’t need one-to-many and many-to-one anymore.

Harsha S
Guest
Harsha S
hey hi all harsha here i do hv small problem with hibernate, its related to the topic under discussion. could u please tell me in Stocks , category , Stock_Category tables for me category remains constant, i don’t wanna change it (means i do have constant category table) so if i create new stocks and add existing categories to it what to do if i try the above its quite works but Category table is unnecessarily getting updated even tho new category is not getting inserted…… i don’t wan any changes to be made on category table. help me with… Read more »
Suhas Gunda
Guest
Suhas Gunda

Hi Harsha,

did you find answer of above question?? I am facing same problem.. If you have answer then please let me know on suhas_ngni@rediffmail.com

Arun
Guest
Arun

Can you please explain the mapping what it means , like

what does this means , what is what it refers to ,

trackback
Hibernate – Many-to-many relationship example (Annotation)

[…] Author: mkyong In this tutorial, it will reuse the entire infrastructure of the previous “Hibernate many to many relationship example – XML mapping” tutorial, enhance it to support […]

nnad
Guest
nnad

the project download is missing a lot of dependent jar files.

Arby
Guest
Arby
MYkong, I love your website. But in this example I’m thinking you simply did something just for the sake of providing an example. IT does not seem practical to have Category store Set where each StockCategory has the (parent) Category repeating in it. Not withstanding the fact that M-M relationship can be broken into 1-M and M-1 relationship, even practically that would seem to be the intent. Stock needs to know all its Categories and Category needs to know all Stocks in it. Finally, and this may be Hibernate thingy, I refuse to accept understand the logic behind making a… Read more »
Rakesh
Guest
Rakesh

Dear All ,

I have just gone through one site, and found the explantion with simple example of Many to Many relation in hibernate using JPA .

http://j2eereference.com/2011/01/many-to-many-mapping-in-hibernate/

SQL tutorial
Guest
SQL tutorial

I am taking up the subject java programming SE. I will try this and maybe if I don’t understand some of the codes, I can ask my professor about it.

carldeltoro
Guest
carldeltoro

if I have an attribute in the table StockCategory date???

Hassan
Guest
Hassan

Actually M-M relationship can be decomposed in to two 1-M relationships, but I do not need this extra effort unless I’ve extra columns in the mapper table that I really need(e.g. date of stock_category).

In M-M , read operations work fine, but save/delete/update is not quite easy!

Turion
Guest
Turion

Normally, a many to many relationship is realized by using the @ManyToMany annotation. So let’s say you have users and roles and each user can have a number of roles, while a certain role can belong to a number of users. Then you would use something like this:

Class User {

@ManyToMany(targetEntity = Role.class)
@JoinTable(name = “user_has_role”,
joinColumns = @JoinColumn(name = “userId”),
inverseJoinColumns = @JoinColumn(name = “roleId”)
)
public Set getRoles() {
return roles;
}

}

Of course you need a third table to map this kind of relationship, but I dont’t understand why you are using the @ManyToOne annotation.

trackback
Hibernate Tutorials | J2EE Web Development Tutorials

[…] Many-to-many relationship example A many-to-many relationship project demonstration. […]

Gaurav
Guest
Gaurav

Thanks for this tutorial,
I am wondering, if it possible, if in this case STOCK_CATEGORY table will be having composite primary key with
CATEGORY_ID and STOCK_ID i.e. no other PK in this case.
Then How will we define many to many relationship.
I am struggling to resolve this scenario.

gary
Guest
gary

hi,

Found the tutorial quite useful. Thanks

please can you also post hibernate many-many CRUD application? For example, Instead of adding a new category, I want to reference existing category in my Stock class, all I need to do is to insert Stock table and into the mapping table.

can you help pls?

sunil
Guest
sunil

You are completely wrong regarding mapping of many-to-many. I dont see anything like many-to-many. You are just trying to give alternate way but not exact code or tutorial. Please verify it since it is misleading the developer….
Thanks
sunil