Hibernate Mappings With hbm.xml Files

SCENARIO: Many authors contribute to one book

• Unidirectional associations – Many-to-one

create table Author ( author_id bigint not null primary key, book_id bigint not null, first_name varchar, last_name varchar )
create table Book ( book_id bigint not null primary key )

Author.book_id is foreign key from Book.

author.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 package="com.mattiz.persistence.beans">
	<class name="Author">
		<id name="authorid" column="author_Id" type="long">
			<generator class="native" />
		</id>
		<property name="firstName" type="string" length="20" column="first_name" />
		<property name="lastName" type="string" length="20" column="last_name" />
		<many-to-one name="book" column="book_Id" class="Book"
			not-null=”true” />
	</class>
</hibernate-mapping>

In the many-to-one tag the name is “book”, so that means that if you use a getter it would be author.getBook() or if you use HQL author.book.
The many to one tag implies that book_id is a foreign key for this relationship

book.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 package="com.mattiz.persistence.beans">
	<class name="Book">
		<id name="bookid" column="book_id" type="long">
			<generator class="native" />
		</id>
	</class>
</hibernate-mapping>
package com.mattiz.persistence.beans;

public class Author implements java.io.Serializable {
	private long authorid;
	private String firstName;
	private String lastName;
	private Book book;

	public Author() {
	}

	public Author(Book book) {
		this.book = book;
	}

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

	public long getAuthorid() {
		return this.authorid;
	}

	public void setAuthorid(long authorid) {
		this.authorid = authorid;
	}

	public String getFirstName() {
		return this.firstName;
	}

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

	public String getLastName() {
		return this.lastName;
	}

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

	public Book getBook() {
		return this.book;
	}

	public void setBook(Book book) {
		this.book = book;
	}
}
package com.mattiz.persistence.beans;

public class Book implements java.io.Serializable {
	private long bookid;

	public Book() {
	}

	public long getBookid() {
		return this.bookid;
	}

	public void setBookid(long bookid) {
		this.bookid = bookid;
	}
}


• Bidirectionality in Many to One

Bidirectional many-to-one

create table Author ( author_id bigint not null primary key, book_id  bigint not null, first_name varchar, last_name varchar )
create table Book ( book_id bigint not null primary key )

Author.book_id is foreign key from Book

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 package="com.mattiz.persistence.beans">
	<class name="Author">
		<id name="authorid" column="author_Id" type="long">
			<generator class="native" />
		</id>
		<property name="firstName" type="string" length="20" column="first_name" />
		<property name="lastName" type="string" length="20" column="last_name" />
		<many-to-one name="book" column="book_Id" class="Book"
			not-null="true" />
<!—book_id is FK in Author table from Book table->
	</class>
</hibernate-mapping>

book.hbml.xml

<hibernate-mapping package="com.mattiz.persistence.beans">
	<class name="Book">
		<id name="bookid" column="book_id" type="long">
			<generator class="native" />
		</id>
		<set name="authors" inverse="true"><!—book_id references column in Author table-->
			<key column="book_id" />
			<one-to-many class="Author" />
		</set>
	</class>
</hibernate-mapping>
package com.mattiz.persistence.beans;

public class Author implements java.io.Serializable {
	private long authorid;
	private String firstName;
	private String lastName;
	private Book book;

	public Author() {
	}

	public Author(Book book) {
		this.book = book;
	}

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

	public long getAuthorid() {
		return this.authorid;
	}

	public void setAuthorid(long authorid) {
		this.authorid = authorid;
	}

	public String getFirstName() {
		return this.firstName;
	}

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

	public String getLastName() {
		return this.lastName;
	}

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

	public Book getBook() {
		return this.book;
	}

	public void setBook(Book book) {
		this.book = book;
	}
}
package com.mattiz.persistence.beans;

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

public class Book implements java.io.Serializable {
	private long bookid;
	private Set authors = new HashSet(0);

	public Book() {
	}

	public Book(Set authors) {
		this.authors = authors;
	}

	public long getBookid() {
		return this.bookid;
	}

	public void setBookid(long bookid) {
		this.bookid = bookid;
	}

	public Set getAuthors() {
		return this.authors;
	}

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

If author in book is many-to-one, book to author is one- to-many and is a set.
The FK to author is the primary key in book.

From book.hbm.xml:

<set name="authors" inverse="true">
	<key column="book_id" />
	<one-to-many class="Author" />
</set>

Let’s consider

<key column=”book_id” />

in book.hbm.xml. Here the key book_id is in the other table, i.e. Author. So getAuthors() will use the book_id column (FK) in the Author table.
So Author has PK author_id and FK book_id while Book has PK book_id. This relationship gets the authors (looked up based on FK book_id) associated with that Book. So authors are looked up based on their FK which is book_id and you get multiple authors which is a set. Basically in a one to many the key has to be in the other table.
the fk in a many to one, the key is in this table
The underlying table structure has to match hibernate’s definition else it will give you a runtime exception.
When you see

<key> 

it means refer to the key in the table where it is an FK.

Here is a simplistic explanation of the references:

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 package="com.mattiz.persistence.beans">
	<class name="ContributingAuthor">
		<id name="id" column="id" type="long">
			<generator class="native" />
		</id>
		<property name="firstName" type="string" length="20" column="first_name" />
		<property name="lastName" type="string" length="20" column="last_name" />
		<many-to-one name="bookContributedToByAuthor" column="book_Id_in_Author"
			class="BookWithMultipleAuthors" not-null="true" />
	</class>
</hibernate-mapping>

book.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 package="com.mattiz.persistence.beans">
	<class name="BookWithMultipleAuthors">
		<id name="id" column="id" type="long">
			<generator class="native" />
		</id>
		<set name="contributingAuthors" inverse="true">
			<key column="book_Id_in_Author" />
			<one-to-many class="ContributingAuthor" />
		</set>
	</class>
</hibernate-mapping>

Generated classes:

package com.mattiz.persistence.beans;

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

public class BookWithMultipleAuthors implements java.io.Serializable {
	private long id;
	private Set contributingAuthors = new HashSet(0);

	public BookWithMultipleAuthors() {
	}

	public BookWithMultipleAuthors(Set contributingAuthors) {
		this.contributingAuthors = contributingAuthors;
	}

	public long getId() {
		return this.id;
	}

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

	public Set getContributingAuthors() {
		return this.contributingAuthors;
	}

	public void setContributingAuthors(Set contributingAuthors) {
		this.contributingAuthors = contributingAuthors;
	}
}
package com.mattiz.persistence.beans;

public class ContributingAuthor implements java.io.Serializable {
	private long id;
	private String firstName;
	private String lastName;
	private BookWithMultipleAuthors bookContributedToByAuthor;

	public ContributingAuthor() {
	}

	public ContributingAuthor(BookWithMultipleAuthors bookContributedToByAuthor) {
		this.bookContributedToByAuthor = bookContributedToByAuthor;
	}

	public ContributingAuthor(String firstName, String lastName,
			BookWithMultipleAuthors bookContributedToByAuthor) {
		this.firstName = firstName;
		this.lastName = lastName;
		this.bookContributedToByAuthor = bookContributedToByAuthor;
	}

	public long getId() {
		return this.id;
	}

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

	public String getFirstName() {
		return this.firstName;
	}

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

	public String getLastName() {
		return this.lastName;
	}

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

	public BookWithMultipleAuthors getBookContributedToByAuthor() {
		return this.bookContributedToByAuthor;
	}

	public void setBookContributedToByAuthor(
			BookWithMultipleAuthors bookContributedToByAuthor) {
		this.bookContributedToByAuthor = bookContributedToByAuthor;
	}
}

Executing a one-to-many book.getAuthors() is the equivalent of writing this sql
select * from t_author where book_id=? Where book_id is the FK in t_author
The book_id would have to be already present in book as a rule via referential integrity
Executing a many to one author.getBook() is the equivalent of writing this sql
select * from t_book where book_id = ? where the parameter in the last query would be from the author table; which would return one (obviously) since you are querying by PK.

• Unidirectional one to one

create table  Author( author_id  bigint not null primary key, book_id  bigint not null unique )
create table Book ( book_id bigint not null primary key )

A unidirectional one-to-one association on a foreign key is almost identical. The only difference is the column unique constraint.
Of course the underlying table structure has to match hibernate’s definition else it will give you a runtime exception.

create table Book ( isbn bigint not null primary key )
create table Author ( isbn bigint not null primary key )
<class name="Book">
<id name="id" column="isbn">
	<generator class="native" />
</id>
</class>
<class name="Author">
	<id name="id" column="isbn">
		<generator class="foreign">
			<param name="property">book</param>
		</generator>
	</id>
	<one-to-one name="book" constrained="true" />
</class>

There are two ways of doing a one-to-one, In the second option the two tables share the same id as the primary key which makes sense since it is a one to one. Both tables have isbn as primary key
One method is by sharing the primary key, the other method is by having a Primarykey and foreign key but enforcing uniqueness on the foreign key. Both isbn ids are generated so they must match, so you see only one has a native generator and the other has a ‘foreign’ generator meaning it relies on the first
If both generate separately they’d get out of synch. We only need to take away that there are two ways of defining a one-to-one
1. Sharing primary key – one table generates the primary key and the other one syncs with the first
2. The other option is to have a PK FK relationship but uniqueness enforced on the FK – so there will only be one.

One attribute that could be useful is the cascade attribute. In a one-to-many or many-to-one relation –
• cascade=”none” means that if saving or deleting first hibernate object has no affect on related objects.
• cascade=”save” means if first object is saved it automatically saves related objects.
• Similarly cascade = “delete” will delete related objects.
• cascade=”all” will save, delete, etc related objects even if they have FK constraints. Everything gets deleted, and hibernate takes care of that.

http://docs.jboss.org/hibernate/core/3.5/reference/en/html/associations.htmlhttp://ndpsoftware.com/HibernateMappingCheatSheet.html

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: