In this Hibernate tutorial, we will learn how to use XML to map a one-to-many association on join table in relational database with Java objects. The following entity relationship diagram depicts the association:
One-to-Many association on a join table
Here, a category can contain from one to many occurrences of article. The CategoryArticle is the join table between them. Let’s see how to model this association in Hibernate framework.
The sample application in this tutorial was developed and tested in the following environment (of course you can use newer versions):
Table of content:
Create a MySQL database called newsdb with three tables: category, article and CategoryArticle (join table), by executing the following script in MySQL Workbench’s SQL Editor:
CREATE DATABASE `newsdb`; use newsdb; CREATE TABLE `category` ( `category_id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(45) NOT NULL, PRIMARY KEY (`category_id`) ); CREATE TABLE `article` ( `article_id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(70) NOT NULL, `description` varchar(250) NOT NULL, `keywords` varchar(150) NOT NULL, `content` text NOT NULL, PRIMARY KEY (`article_id`) ); CREATE TABLE `categoryarticle` ( `category_id` int(11) NOT NULL, `article_id` int(11) NOT NULL, PRIMARY KEY (`category_id`,`article_id`), KEY `fk_category` (`category_id`), KEY `fk_article` (`article_id`), CONSTRAINT `fk_article` FOREIGN KEY (`article_id`) REFERENCES `article` (`article_id`), CONSTRAINT `fk_category` FOREIGN KEY (`category_id`) REFERENCES `category` (`category_id`) );
If you are using MySQL Command Line Client, type the following command:
source Path\To\The\Script\File\MySQLscript.sql
Create the MySQLscript.sql file from the above script or find it in the attached project. The database newsdb will have the following structure:
Create a Java project in Eclipse IDE called HibernateOne2ManyJoinTableXMLExample with the following structure:
We will create/add to this project the following files:
Find the Hibernate and MySQL jar files from their distribution archives.
Create two Java files Category.java and Article.java corresponding to the tables category and article:
File net\codejava\hibernate\Category.java:
package net.codejava.hibernate; import java.util.Set; public class Category { private long id; private String name; private Set<Article> articles; public Category() { } public Category(String name) { this.name = name; } // getters and setters... }
File net\codejava\hibernate\Article.java:
package net.codejava.hibernate; public class Article { private long id; private String title; private String description; private String keywords; private String content; private Category category; public Article() { } public Article(String title, String description, String keywords, String content, Category category) { this.title = title; this.description = description; this.keywords = keywords; this.content = content; this.category = category; } // getters and setters... }
NOTES: The Category class has a set of articles and the Article class has a reference to its category. This is a typical configuration for a bidirectional one-to-many association. And note that we don’t have to write model class for the join table.
Create two Hibernate mapping files Category.hbm.xml and Article.hbm.xml with the following content:
File net\codejava\hibernate\Category.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="net.codejava.hibernate"> <class name="Category" table="CATEGORY"> <id name="id" column="CATEGORY_ID"> <generator class="native"/> </id> <property name="name" column="NAME" /> <set name="articles" table="CategoryArticle" cascade="all"> <key column="CATEGORY_ID" not-null="true" /> <many-to-many column="ARTICLE_ID" class="Article" unique="true"/> </set> </class> </hibernate-mapping>
File net\codejava\hibernate\Article.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="net.codejava.hibernate"> <class name="Article" table="ARTICLE"> <id name="id" column="ARTICLE_ID"> <generator class="native"/> </id> <property name="title" column="TITLE" /> <property name="description" column="DESCRIPTION" /> <property name="keywords" column="KEYWORDS" /> <property name="content" column="CONTENT" /> <join table="CategoryArticle" inverse="true"> <key column="ARTICLE_ID"/> <many-to-one name="category" column="CATEGORY_ID" not-null="true"/> </join> </class> </hibernate-mapping>
NOTES:
Write code for the Hibernate configuration file (hibernate.cfg.xml) as follows:
<?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> <!-- Database connection settings --> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost:3306/newsdb</property> <property name="connection.username">root</property> <property name="connection.password">secret</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <property name="show_sql">true</property> <mapping resource="net/codejava/hibernate/Category.hbm.xml"/> <mapping resource="net/codejava/hibernate/Article.hbm.xml"/> </session-factory> </hibernate-configuration>
You may need to change the username and password according to your MySQL account.
To wire all the above pieces together, create a test program that persists some sample data as follows:
package net.codejava.hibernate; import java.util.HashSet; import java.util.Set; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; /** * This program demonstrates how to use Hibernate framework to manage * a one-to-many association on a join table. * @author www.codejava.net * */ public class ArticlesManager { public static void main(String[] args) { // loads configuration and mappings Configuration configuration = new Configuration().configure(); ServiceRegistryBuilder registry = new ServiceRegistryBuilder(); registry.applySettings(configuration.getProperties()); ServiceRegistry serviceRegistry = registry.buildServiceRegistry(); // builds a session factory from the service registry SessionFactory sessionFactory = configuration .buildSessionFactory(serviceRegistry); // obtains the session Session session = sessionFactory.openSession(); session.beginTransaction(); Category category = new Category("Hibernate Framework"); Article articleOne = new Article("One-to-One Mapping", "One-to-One XML Mapping Tutorial", "Hibernate,One-to-One", "Content of One-to-One XML Mapping Tutorial", category); Article articleTwo = new Article("One-to-Many Mapping", "One-to-Many XML Mapping Tutorial", "Hibernate,One-to-Many", "Content of One-to-Many XML Mapping Tutorial", category); Article articleThree = new Article("Many-to-Many Mapping", "Many-to-Many XML Mapping Tutorial", "Hibernate,Many-to-Many", "Content of Many-to-Many XML Mapping Tutorial", category); Set<Article> articles = new HashSet<Article>(); articles.add(articleOne); articles.add(articleTwo); articles.add(articleThree); category.setArticles(articles); session.save(category); session.getTransaction().commit(); session.close(); } }
Output of the program:
Hibernate: insert into CATEGORY (NAME) values (?)
Hibernate: insert into ARTICLE (TITLE, DESCRIPTION, KEYWORDS, CONTENT) values (?, ?, ?, ?)
Hibernate: insert into ARTICLE (TITLE, DESCRIPTION, KEYWORDS, CONTENT) values (?, ?, ?, ?)
Hibernate: insert into ARTICLE (TITLE, DESCRIPTION, KEYWORDS, CONTENT) values (?, ?, ?, ?)
Hibernate: insert into CategoryArticle (CATEGORY_ID, ARTICLE_ID) values (?, ?)
Hibernate: insert into CategoryArticle (CATEGORY_ID, ARTICLE_ID) values (?, ?)
Hibernate: insert into CategoryArticle (CATEGORY_ID, ARTICLE_ID) values (?, ?)
Result in the category table:
Result in the article table:
Result in the CategoryArticle table:
You can get the code examples on GitHub, or download the sample project attached below.