Many To Many Hibernate Mapping using mapping table

We consider the scenario where one author can write many books and one book can have many authors. This is a many to many relationship that uses a mapping table to manage the many to many associations between authors and books.
The following queries can setup such a database for you.

drop database pubs;
create database pubs;
use pubs;
drop table TB_AUTHORS;
CREATE TABLE TB_AUTHORS (AUTHOR_ID int(11) NOT NULL default '0',AUTHOR_NAME varchar(30) default NULL,PRIMARY KEY (AUTHOR_ID)) ;
drop table TB_BOOKS;
CREATE TABLE TB_BOOKS (ISBN_CODE varchar(10) NOT NULL, BOOK_TITLE varchar(30) default NULL,PRIMARY KEY (ISBN_CODE)) ;
drop table TB_AUTHORS_BOOKS;
CREATE TABLE TB_AUTHORS_BOOKS (AUTHOR_ID_IN_MAP int(11) NOT NULL, ISBN_CODE varchar(10) not NULL);

The domain classes look like this

package com.mattiz.persistence.beans;
// Generated 18 Jan, 2014 6:01:04 AM by Hibernate Tools 3.2.2.GA


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

/**
 * Author generated by hbm2java
 */
public class Author  implements java.io.Serializable {
     private int authorId;
     private Set books = new HashSet(0);
     private String name;

    public Author() {
    }

    public Author(Set books, String name) {
       this.books = books;
       this.name = name;
    }
   
    public int getAuthorId() {
        return this.authorId;
    }
    
    public void setAuthorId(int authorId) {
        this.authorId = authorId;
    }
    public Set getBooks() {
        return this.books;
    }
    
    public void setBooks(Set books) {
        this.books = books;
    }
    public String getName() {
        return this.name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
}
package com.mattiz.persistence.beans;
// Generated 18 Jan, 2014 6:01:04 AM by Hibernate Tools 3.2.2.GA



/**
 * Book generated by hbm2java
 */
public class Book  implements java.io.Serializable {
     private String isbn;
     private String title;

    public Book() {
    }
	
    public Book(String isbn) {
        this.isbn = isbn;
    }
    public Book(String isbn, String title) {
       this.isbn = isbn;
       this.title = title;
    }
   
    public String getIsbn() {
        return this.isbn;
    }
    
    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }
    public String getTitle() {
        return this.title;
    }
    
    public void setTitle(String title) {
        this.title = title;
    }
}

The above class files are generated from the hbm2java tool(See details at bottom)
The corresponding hbm files look like this
Author.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.mattiz.persistence.beans.Author" lazy="false" table="TB_AUTHORS" >
        <id name="authorId" column="AUTHOR_ID" length="11" type="int" >
        	<generator class="increment"></generator>
        </id>
        <set name="books" table="TB_AUTHORS_BOOKS" cascade="save-update" lazy="false">
            <key column="AUTHOR_ID_IN_MAP" />
            <many-to-many column="ISBN_CODE"  class="com.mattiz.persistence.beans.Book" />
        </set>
        <property name="name" type="java.lang.String" column="AUTHOR_NAME" length="30" />
    </class>
</hibernate-mapping>

Book.hbml.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.mattiz.persistence.beans.Book" table="TB_BOOKS" lazy="false">
		<id name="isbn" column="ISBN_CODE" length="10" type="java.lang.String" >
			<generator class="assigned"></generator>
		</id>
		<property name="title" type="java.lang.String" column="BOOK_TITLE" length="30" />
	</class>
</hibernate-mapping>

The Dao class and interface:
IMattizDao.java

package com.mattiz.persistence.data;

import java.util.Set;

import org.springframework.dao.DataAccessException;

import com.mattiz.persistence.beans.Author;
import com.mattiz.persistence.beans.Book;

public interface IMattizDao {

	public Set<Book> getBooksForAuthor(int authorId) throws DataAccessException;

	public void insertAuthor(String authorName, Set<Book> books)
			throws DataAccessException;

}

MattizDao.java

package com.mattiz.persistence.data;

import java.util.Set;

import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateTemplate;

import com.mattiz.persistence.beans.Author;
import com.mattiz.persistence.beans.Book;

public class MattizDao implements IMattizDao {

	private HibernateTemplate hibernateTemplate;

	public Set<Book> getBooksForAuthor(int authorId) throws DataAccessException {
		Author authorBean = null;
		authorBean = (Author) getHibernateTemplate().load(Author.class,
				authorId);
		System.out.println(authorBean.getName()+"n");
		Set<Book> books = authorBean.getBooks();
		for(Book b: books){
			System.out.println(b.getTitle());
		}	
		return books;
	}

	public void insertAuthor(String authorName, Set<Book> books)
			throws DataAccessException {
		Author authorBean = new Author();
		authorBean.setBooks(books);
		authorBean.setName(authorName);
		HibernateTemplate template = getHibernateTemplate();
		template.saveOrUpdate(authorBean);
		System.out.println("Inserted/Updated AuthorBean "
				+ authorBean.getName());
	}

	public HibernateTemplate getHibernateTemplate() {
		return hibernateTemplate;
	}

	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}
}

The service class and interface
IMattizDelegate.java

package com.mattiz.service.spring;

import java.util.Set;

import com.mattiz.persistence.beans.Book;
import com.mattiz.persistence.data.IMattizDao;

public interface IMattizDelegate {

	public void insertAuthor(String authorName, Set<Book> books);

	public Set<Book> getBooksForAuthor(int authorId);

	public IMattizDao getMattizDao();

	public void setMattizDao(IMattizDao mattizDao);

}

MattizDelegate.java

package com.mattiz.service.spring;

import java.util.Set;

import com.mattiz.persistence.beans.Book;
import com.mattiz.persistence.data.IMattizDao;

public class MattizDelegate implements IMattizDelegate {

	private IMattizDao mattizDao;

	public void insertAuthor(String authorName, Set<Book> books) {
		getMattizDao().insertAuthor(authorName, books);
	}

	public Set<Book> getBooksForAuthor(int authorId) {
		Set<Book> books = getMattizDao().getBooksForAuthor(authorId);
		return books;
	}

	public IMattizDao getMattizDao() {
		return mattizDao;
	}

	public void setMattizDao(IMattizDao mattizDao) {
		this.mattizDao = mattizDao;
	}

}

The Main class that is a replacement for a front end UI
MattizMain.java

package com.mattiz.web.managedbeans;

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

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.mattiz.persistence.beans.Book;
import com.mattiz.service.spring.IMattizDelegate;

public class MattizMain {

	private ApplicationContext applicationContext;

	private IMattizDelegate mattizDelegate;

	public IMattizDelegate getMattizDelegate() {
		mattizDelegate = (IMattizDelegate) applicationContext
				.getBean("mattiz.service.delegate");
		return mattizDelegate;
	}

	public void setMattizDelegate(IMattizDelegate mattizDelegate) {
		this.mattizDelegate = mattizDelegate;
	}

	public ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	public void setApplicationContext(ApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
	}

	public static void main(String[] args) {
		MattizMain mattizMain = new MattizMain();
		mattizMain.applicationContext = new ClassPathXmlApplicationContext(
				"resources/mattiz.xml");
		Book a = new Book("1e","The Cool Drink");
		Book b = new Book("1a","Lost Island");
		Book c = new Book("1b","Treasure Hunt");
		Book d = new Book("1c","Down With Fever");
		Book e = new Book("1d","Imagination runs Wild");
		Book f = new Book("1r","The Wild West");
		Book g = new Book("1h","Gregorios");
		Book h = new Book("14","Mar Thoma");
		Book i = new Book("15","Christ and the Disciples");
		Book j = new Book("1t","Long live His Cotton Socks");
		Book k = new Book("19","Praise Be to Harman!");
		Set<Book> aa = new HashSet<Book>();
		aa.add(a);
		aa.add(b);
		aa.add(c);		
		aa.add(d);
		aa.add(e);
		aa.add(f);
		aa.add(g);
		Set<Book> ab = new HashSet<Book>();
		ab.add(a);		
		ab.add(b);
		ab.add(h);
		Set<Book> ac = new HashSet<Book>();
		ac.add(i);
		ac.add(j);		
		ac.add(k);
		Set<Book> ad = new HashSet<Book>();
		ad.add(a);		
		ad.add(k);	
		Set<Book> af = new HashSet<Book>();
		af.add(a);
		Set<Book> ag = new HashSet<Book>();
		ag.add(a);	
		Set<Book> ah = new HashSet<Book>();
		ah.add(e);	
		Set<Book> aj = new HashSet<Book>();
		aj.add(f);	
		mattizMain.getMattizDelegate().insertAuthor("Mac",aa);
		mattizMain.getMattizDelegate().insertAuthor("Kenzie", ab);
		mattizMain.getMattizDelegate().insertAuthor("John",ac);		
		mattizMain.getMattizDelegate().insertAuthor("Warbler",ad);
		mattizMain.getMattizDelegate().insertAuthor("Huan",af);
		mattizMain.getMattizDelegate().insertAuthor("Mike",ag);
		mattizMain.getMattizDelegate().insertAuthor("Don",ag);		
		mattizMain.getMattizDelegate().insertAuthor("John",ah);
		mattizMain.getMattizDelegate().insertAuthor("Mark",aj);
		mattizMain.getMattizDelegate().insertAuthor("Jim",ah);
		mattizMain.getMattizDelegate().insertAuthor("Joe",ah);
		mattizMain.getMattizDelegate().insertAuthor("Harry",ad);		
		mattizMain.getMattizDelegate().insertAuthor("Noman",ag);
		mattizMain.getMattizDelegate().insertAuthor("Julian",aj);
		mattizMain.getMattizDelegate().insertAuthor("Tick",af);
		mattizMain.getMattizDelegate().insertAuthor("Toe",ac);
		mattizMain.getMattizDelegate().getBooksForAuthor(1);
		System.out.println("----------------------");
		mattizMain.getMattizDelegate().getBooksForAuthor(5);
	}

}

Spring configuration file:
mattiz.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean
        id="mattiz.hibernate.dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" >
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/pubs" />
        <property name="user" value="root" />
        <property name="password" value="admin" />
    </bean>
    <bean id="mattiz.abstract.hibernate.sessionfactory" abstract="true" 
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" lazy-init="true" >
        <property name="dataSource" >
            <ref local="mattiz.hibernate.dataSource" />
        </property>
        <property name="hibernateProperties" >
            <props>
                <prop key="hibernate.dialect" >org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql" >false</prop>
            </props>
        </property>
    </bean>
    <bean id="mattiz.pageSize" class="java.lang.Integer" >
        <constructor-arg value="5000" >
        </constructor-arg>
    </bean>
    <bean id="mattiz.hibernate.sessionfactory" parent="mattiz.abstract.hibernate.sessionfactory" >
        <property name="mappingResources" >
            <list>
                <value>resources/Author.hbm.xml</value>
                <value>resources/Book.hbm.xml</value>
            </list>
        </property>
    </bean>
    <bean id="mattiz.transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" >
        <property name="sessionFactory" >
            <ref bean="mattiz.hibernate.sessionfactory" />
        </property>
    </bean>
    <bean id="mattiz.hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate" >
        <property name="sessionFactory" >
            <ref bean="mattiz.hibernate.sessionfactory" />
        </property>
    </bean>
    <bean id="mattiz.dao.mattizDAO" class="com.mattiz.persistence.data.MattizDao" singleton="true" >
        <property name="hibernateTemplate" >
            <ref bean="mattiz.hibernateTemplate" />
        </property>
    </bean>
    <bean id="mattiz.client" class="com.mattiz.web.managedbeans.MattizMain" singleton="true" >
        <property name="mattizDelegate" ref="mattiz.service.delegate" />
    </bean>
    <bean id="mattiz.service.delegate" class="com.mattiz.service.spring.MattizDelegate" singleton="true" >
        <property name="mattizDao" ref="mattiz.dao.mattizDAO" />
    </bean>
</beans>

Screenshots show structure of file heirarchy, jars and APIs used and SQL output
many_many
library_ref
mapping_table_insertions

The domain files are generated from the hbml.xml hibernate files. For easy reference the code is given below:
The Author.hbm.xml and Book.hbm.xml described above are placed in the “src” folder. The generated java domain classes are created under “generated/src/com/mattiz/persistence/beans” folder.
The jars used for this purpose can be seen in the screenshot.
The only additional piece of code is the build file described below:

build.xml

<?xml version="1.0" encoding="UTF-8"?>
<project default="codegen">
	<target name="codegen">
		<path id="classpath_id">
<pathelement location="I:packagesspring-framework-3.0.2.RELEASE-dependenciesorg.apache.commonscom.springsource.org.apache.commons.beanutils1.8.0com.springsource.org.apache.commons.beanutils-1.8.0.jar" />
<pathelement location="I:packagesspring-framework-3.0.2.RELEASE-dependenciesorg.apache.commonscom.springsource.org.apache.commons.logging1.1.1com.springsource.org.apache.commons.logging-1.1.1.jar" />
<pathelement location="I:packagesspring-framework-3.0.2.RELEASE-dependenciesorg.dom4jcom.springsource.org.dom4j1.6.1com.springsource.org.dom4j-1.6.1.jar" />
<pathelement location="I:packagesspring-framework-3.0.2.RELEASE-dependenciesorg.hibernatecom.springsource.org.hibernate3.3.1.GAcom.springsource.org.hibernate-3.3.1.GA.jar" />
<pathelement location="I:packagesspring-framework-3.0.2.RELEASE-dependenciesorg.hibernatecom.springsource.org.hibernate.annotations3.4.0.GAcom.springsource.org.hibernate.annotations-3.4.0.GA.jar" />
<pathelement location="I:packagesspring-framework-3.0.2.RELEASE-dependenciesorg.apache.log4jcom.springsource.org.apache.log4j1.2.15com.springsource.org.apache.log4j-1.2.15.jar" />
<pathelement location="I:packagesspring-framework-3.0.2.RELEASE-dependenciesorg.apache.commonscom.springsource.org.apache.commons.collections3.2.1com.springsource.org.apache.commons.collections-3.2.1.jar" />
<pathelement location="I:packagesspring-framework-3.0.2.RELEASE-dependenciesorg.slf4jcom.springsource.slf4j.api1.5.3com.springsource.slf4j.api-1.5.3.jar" />
<pathelement location="I:packagesspring-framework-3.0.2.RELEASE-dependenciesorg.slf4jcom.springsource.slf4j.jcl1.5.3com.springsource.slf4j.jcl-1.5.3.jar" />
<pathelement location="I:packageshibernate-tools.jarhibernate-tools.jar" />
<pathelement location="I:packagesspring-framework-3.0.2.RELEASE-dependenciesorg.freemarkercom.springsource.freemarker2.3.15com.springsource.freemarker-2.3.15.jar" />
		</path>
		<echo>Zippzip</echo>
		<taskdef name="hibernatetool" classname="org.hibernate.tool.ant.HibernateToolTask">
			<classpath refid="classpath_id" />
		</taskdef>
		<hibernatetool destdir="generated/src">
			<configuration>
				<fileset dir=".">
					<include name="src/*.hbm.xml" />
				</fileset>
			</configuration>
			<hbm2java />
		</hibernatetool>
	</target>
</project>

DomainGenerator

The hibernate domain generator can be downloaded here

The many to many hibernate mapping source code can be downloaded here

About cuppajavamattiz
Matty Jacob - Avid technical blogger with interests in J2EE, Web Application Servers, Web frameworks, Open source libraries, Relational Databases, Web Services, Source control repositories, ETL, IDE Tools and related technologies.

Comments are closed.

%d bloggers like this: