One to Many Bi-Directional Hibernate Relations

I have modified the previous standalone Hibernate application to indicate how a one to many bi-relation between objects is handled in Hibernate http://cuppajavamattiz.com/2008/07/04/one-to-many-hibernate-relations/ I am using the same database setup and the jars as earlier.

I am only including source code for the DAO class and the domain classes and the hbm.xml files for simplicity. The client code can be rewritten using code in the previous code as a base.

The DAO class:

package com.mattiz.persistence.data;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
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 AuthorBookLookupBean {
    private HibernateTemplate hibernateTemplate;
 
    public void insertBook() throws DataAccessException {
        HibernateTemplate template = getHibernateTemplate();
        Book book = new Book();
        book.setIsbnCode("124");
        book.setTitle("The Dodo");
        book.setAuthors(new HashSet());
        book.getAuthors().add(new Author("Roy", "John", book));
        book.getAuthors().add(new Author("James", "Joyce", book));
        book.getAuthors().add(new Author("Jill", "Joyce", book));
        book.getAuthors().add(new Author("Amy", "Watt", book));
        book.getAuthors().add(new Author("Matt", "Tizz", book));
        template.save(book);
    }
 
    public void getAuthorsFromBook() throws DataAccessException {
 
        String isbn = "124";
        Book book = (Book) getHibernateTemplate().load(Book.class, isbn);
        Set authors = book.getAuthors();
        Iterator iterator = authors.iterator();
        while (iterator.hasNext()) {
            Author author = (Author) iterator.next();
            System.out.println("FIRST NAME " + author.getFirstName());
            System.out.println("SECOND NAME " + author.getLastName());
        }
    }
 
    public void getBookFromAuthors() throws DataAccessException {
        String authorFirstName = "Matt";
        List list = (List) getHibernateTemplate().find(
                "from Author author where author.firstName = ?",
                authorFirstName);
        for (int i = 0; i < list.size(); i++) {
            Author author = (Author) list.get(i);
            Book book = author.getBook();
            System.out.println(book.getTitle());
        }
    }
 
    public HibernateTemplate getHibernateTemplate() {
        return hibernateTemplate;
    }
 
    public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
        this.hibernateTemplate = hibernateTemplate;
    }
}

The Author Domain class:

package com.mattiz.persistence.beans;

public class Author {
	public Author() {
	}

	public Author(String first, String last, Book book) {
		this.firstName = first;
		this.lastName = last;
		this.book = book;
	}

	private Book book;
	private String firstName;
	private String lastName;
	private long id;

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public long getId() {
		return id;
	}

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

	public Book getBook() {
		return book;
	}

	public void setBook(Book book) {
		this.book = book;
	}
}

The Book Domain class:(Book.java is actually identical to the one in the previous post)

package com.mattiz.persistence.beans;

import java.util.Set;

public class Book {
	private String isbnCode;
	private String title;
	private Set authors;

	public String getIsbnCode() {
		return isbnCode;
	}

	public void setIsbnCode(String isbnCode) {
		this.isbnCode = isbnCode;
	}

	public Set getAuthors() {
		return authors;
	}

	public void setAuthors(Set authors) {
		this.authors = authors;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}
}

The 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" table="TB_AUTHOR"
        lazy="false">
        <id name="id" column="UID" type="long">
            <generator class="increment" />
        </id>
        <property name="firstName" type="java.lang.String" column="FIRST_NAME"
            length="25" />
        <property name="lastName" type="java.lang.String" column="LAST_NAME"
            length="25" />
        <b>
            <many-to-one name="book" column="BOOK_ID" not-null="true" />
        </b>
    </class>
</hibernate-mapping>

The 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_BOOK"
        lazy="false">
        <id name="isbnCode" column="ISBN_CODE" type="string">
            <generator class="assigned" />
        </id>
 
        <b>
            <set name="authors" cascade="save-update" lazy="false" inverse="true">
            </B>
                <key column="BOOK_ID" />
                <one-to-many class="com.mattiz.persistence.beans.Author" />
            </set>
            <property name="title" type="java.lang.String" column="TITLE"
                length="50" />
    </class>
</hibernate-mapping>

The configuration file mattiz.xml has a small change:

<?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/AUTHORS" />
        <property name="user" value="admin" />
        <property name="password" value="admin" />
    </bean>
    <bean id="mattiz.abstract.hibernate.sessionfactory"
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
        abstract="true" 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>
    <b>
        <bean id="mattiz.mattizDAO" class="com.mattiz.persistence.data.AuthorBookLookupBean"
            singleton="true">
    </b>
    <property name="hibernateTemplate">
        <ref bean="mattiz.hibernateTemplate" />
    </property>
</bean>
    <bean id="mattiz.client" class="com.mattiz.web.managedbeans.AuthorSearchCreateBean"
        singleton="true">
        <property name="serviceManager" ref="mattiz.service.manager" />
    </bean>
    <bean id="mattiz.service.manager" class="com.mattiz.service.spring.DefaultServiceManager"
        singleton="true">
        <property name="authorLookup" ref="mattiz.mattizDAO" />
    </bean>
</beans>

Output looks something like this:

FIRST NAME Amy
SECOND NAME Watt
FIRST NAME Jill
SECOND NAME Joyce
FIRST NAME Roy
SECOND NAME John
FIRST NAME Matt
SECOND NAME Tizz
FIRST NAME James
SECOND NAME Joyce
The Dodo

You would have to clean the data in the database after each run to avoid constraint violations, or better still modify the code above to handle that!

I still get a classic Lazy Initialization Exception I mentioned in the earlier post for lazy=”true”.