In our last article, we have explained you how to perform a one-to-many mapping of objects between two Entity classes using Hibernate annotations.
Today we are going to understand how to perform a one-to-many mapping of objects between two Entity classes
using Hibernate's mapping resource file, instead of using its annotations.
One-to-Many relationship is all about how an object of one class is associated with multiple objects of another class.
To understand one-to-one mapping, let's take an example of two Entity classes - User_Details and Mobile_Num, where objects of both Entity classes
are stored in separated database tables and each user object of User_Details is associated with multiple objects of Mobile_Num.
Let's put this example to work and make it easier for you to understand.
Note :
In the upcoming example, We are going to create a few Java classes(Entity classes) which will be mapped to separate tables in our database(Oracle Express Edition 10g).
To perform this, we are not going to use Hibernate Annotations, we will instead create the mapping-resource file with extension hbm.xml.
And yes, one more thing, we are going to create this program in an Eclipse Integrated Development Environment (IDE),
so you may use any IDE of your choice.
Creating a primary Entity class
We are going to create a class that will contain all the Java code files
representing our Model class(whose objects needs to be persisted)
and the class that calls the Hibernate API and create an object-relational mapping(ORM) and perform object persistence.
This is a simple Java class whose objects needs to be persisted/saved, these objects are also known as Plain Old Java Objects(POJO) or Entity class.
Some may even refer to such class whose objects needs to be persisted as the Model class.
User_Details.java
package decodejava;
import java.util.ArrayList;
import java.util.List;
public class User_Details
{
private int id;
private String firstName;
private String lastName;
private List<Mobile_Num> mob= new ArrayList<Mobile_Num>();
public List<Mobile_Num> getMob()
{
return mob;
}
public void setMob(List<Mobile_Num> mob)
{
this.mob = mob;
}
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = 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;
}
}
Advertisement
Creating the secondary Entity class
Next, we are going to create the child Entity class whose objects will also be persisted in a separate database table.
The object of this class will contain a specific piece information about each user, such as -
mobile id and mobile number. This class is also an entity class.
Mobile_Num.java
package decodejava;
public class Mobile_Num
{
private int id;
private int mobile_number;
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public int getMobile_number()
{
return mobile_number;
}
public void setMobile_number(int mobile_number)
{
this.mobile_number = mobile_number;
}
}
Creating the class that calls the Hibernate API
This class will create some User_Details objects , which will be persisted using the Hibernate API and an
object-relational mapping(ORM) in the database is performed.
The Hiber class creates a Configuration object, used to configure the Hibernate. This is the first object we use when using the Hibernate.
This object is used to specify the location of a configuration file and
mapping document used by Hibernate. Using Configuration object we can create a SessionFactory object, which is eventually used to create a Session
object to perform the object persistence operations.
Hiber.java
package decodejava;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Hiber1
{
public static void main(String... ar)
{
Configuration config = new Configuration();
SessionFactory sf = config.configure().buildSessionFactory();
Session session = sf.openSession();
//Creating the first User details
User_Details1 user1 = new User_Details1();
user1.setFirstName("First");
user1.setLastName("User");
//Creating the first mobile info for the user
Mobile_Num mob1 = new Mobile_Num();
mob1.setMobile_number(1111111);
//Creating the second mobile info for the user
Mobile_Num mob2 = new Mobile_Num();
mob2.setMobile_number(2222222);
//mob2.setUser(user2);
List<Mobile_Num> collection = new ArrayList<Mobile_Num>();
collection.add(mob1);
collection.add(mob2);
//Setting the collection of mobiles to a user
user1.setMob(collection);
session.beginTransaction();
session.save(user1); //Saving the first User_Details object
//Retrieve and displaying the user details
user1 = (User_Details1)session.get(User_Details1.class,1);
System.out.println("Retrieving the saved objects");
//Retrieving details of the user.
System.out.println("First User");
System.out.println("User Id : " + user1.getId());
System.out.println("First Name : " + user1.getFirstName());
System.out.println("Last Name : " +user1.getLastName());
collection = (List<Mobile_Num>) user1.getMob();
mob1 = collection.get(0);
System.out.println("Mobile id : " + mob1.getId());
System.out.println("Mobile number : " + mob1.getMobile_number());
mob2 = collection.get(1);
System.out.println("Mobile id : " + mob2.getId());
System.out.println("Mobile number : " + mob2.getMobile_number());
session.getTransaction().commit();
session.close();
}
}
Adding JARs
We are going to add some JARs files to the build path of our Java project.
These JARs make the Hibernate work with our database using a specific JDBC Driver for our particular
database.
All these JARs are included in the folder named required(within our Hibernate installation folder).
So, we need to add all the JARs in the required to our build path of our Java project.
Finally, we are going to add one more JAR file.
This is a specific JDBC JAR file(ojdbc14.jar) required by Hibernate to connect to our database(Oracle Express Edition 10g) and perform
object-relational mapping and object persistence.
Following the same steps using which we created and added the configuration file in our project,
we are going to create and add a mapping-resource file for each Entity class within our package decodejava.
This file allows Hibernate to map the Model/Entity class to a table in the database and perform the object-relational mapping. Hence, we have created two mapping resource document.
userdetails.hbm.xml corresponding to User_Details Entity class.
mobilenum.hbm.xml for Mobile_Num Entity class.
This mapping document ends with an extension .hbm.xml.
userdetails.hbm.xml
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name = "decodejava.User_Details1" table = "USER_DETAILS">
<id name = "id" column = "USER_ID" type = "int">
<generator class="increment"/>
</id>
<property name = "firstName" column = "First_Name" type = "string"/>
<property name = "lastName" column = "Last_Name" type = "string"/>
<list name ="mob" cascade="all">
<key> <column name="USER_ID"> </column> </key>
<list-index column="MOB_ORDER" base="1"/>
<one-to-many class="decodejava.Mobile_Num"/>
</list>
</class>
</hibernate-mapping>
mobilenum.hbm.xml
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name = "decodejava.Mobile_Num" table = "MOBILE_NUM">
<id name = "id" column = "MOBILE_ID" type = "int">
<generator class="sequence">
</generator>
</id>
<property name = "mobile_number" column = "Mobile_Number" type = "int"/>
</class>
</hibernate-mapping>
This mapping document has <hibernate-mapping> as the root element and its child element <class>, containing all the class elements.
The name attribute within the <class> element defines the name of the class to be mapped to a database table.
The table attribute within the <class> element defines the name of database table to be created for the class.
The id element maps a property within the class to the primary key of the database table.
The name child attribute refers to the name of a property in the class.
The column child attribute refers to name of a column in the database table.
The type child attribute specifies the data type of the property within the class, which will be mapped to SQL data type.
The property element maps a property within the class to a column in the database table.
the name child attribute refers to the name of a property in the class.
The column child attribute refers to the column name in the database table.
The list element maps a collection object of type List to a database table.
the name child attribute refers to the name of a Collection property in the class.
The cascade child attribute specifies how the actions that are performed on the parent or primary Entity class
are cascaded to the child or secondary Entity class, where value all means that all the actions performed on the primary Entity class will be automatically cascaded to the secondary Entity class
involved in a relationship.
the key child attribute described the name of a property of the class.
The column child attribute refers to the foreign key column .
The list-index child attribute is used when we are mapping a list or a map Collection,
where column refers to the column for index values and base refers to the starting number of the index.
The <one-to-many> element maps a one-to-many relationship between the object of two classes, i.e.
each object of a class is associated with a multiple object of another class.
The class child attribute refers name of the class which is part of this one-to-many relationship.
Adding a configuration file
Next, we are going to add a configuration file to our project.
This configuration document ends with an extension .cfg.xml,
and it is named as hibernate.cfg.xml.
This configuration file is an xml file and it allows us to specify the following features -
A database to which Hibernate connects to perform object-relational mapping and object persistence.
The JDBC driver class for our specific database, used by the Hibernate to connect to the database.
The username and password of database, using which the Hibernate connects to the database.
An SQL Dialect, used by the Hibernate to instruct the database.
A Entity/POJO class which will be mapped to a database table by Hibernate.
A command to echo all the SQL commands which are executed by the Hibernate on stdout.
The mapping resource file used by Hibernate to correctly map both the Entity classes to their separate database tables.
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>
<!-- Database connection settings -->
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="connection.url">jdbc:oracle:thin:@localhost:1521:XE</property>
<property name="connection.username">scott</property>
<property name="connection.password">tiger</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>
<!--Naming the mapping resource file -->
<mapping resource="userdetails.hbm.xml"/>
<mapping resource="mobilenum.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Directory Structure of Hibernate Project
The picture above depicts how and where to arrange POJO/Entity(.java) file, a secondary Entity (.java) class file and the other the class(that calls the hibernate into action)
in a specific directory structure.
Project Folder - HibernateOneToManyMapping is the name of our Project and it is a top-level directory.
This project folder contains the main package of our project i.e. decodejava,
which contains the parent POJO/Entity class file i.e. User_Details.java, the secondary Entity class i.e. Mobile_Num.java
and the class that calls the hibernate into action i.e. Hiber.java.
Besides this, the project folder also contains the hibernate configuration file i.e. hibernate.cfg.xml, and
the mapping-resource files
named userdetails.hbm.xml and mobilenum.hbm.xml .
The project folder also contains all the needed Hibernate JARs present in the required folder of Hibernate
installation and the JDBC JAR file(ojdbc14.jar) required by Hibernate to connect to our database.
Execution
Finally, after executing Hiber class, two separate tables will be created in the database -
USER_DETAILS, representing object-relational mapping(ORM) for User_Details class.
MOBILE_NUM, representing object-relational mapping(ORM) for Mobile_Num class displaying
one-to-many relationship from USER_DETAILS to MOBILE_NUM
Hence, when you execute the Hiber.java class, you will see the following output which shows one-to-many mapping .
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate: create sequence id_seq start with 1 increment by 1
Hibernate: create table MOBILE_NUM (MOBILE_ID number(10,0) not null, mobile_number number(10,0) not null, USER_ID number(10,0), primary key (MOBILE_ID))
Hibernate: create table USER_DETAILS (USER_ID number(10,0) not null, First_Name varchar2(255 char), Last_Name varchar2(255 char), primary key (USER_ID))
Hibernate: alter table MOBILE_NUM add constraint FKq26cahdr6ogqve5cli5lvy09o foreign key (USER_ID) references USER_DETAILS
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: select id_seq.nextval from dual
Hibernate: select id_seq.nextval from dual
Hibernate: insert into USER_DETAILS (First_Name, Last_Name, USER_ID) values (?, ?, ?)
Hibernate: insert into MOBILE_NUM (mobile_number, MOBILE_ID) values (?, ?)
Hibernate: insert into MOBILE_NUM (mobile_number, MOBILE_ID) values (?, ?)
Hibernate: update MOBILE_NUM set USER_ID=? where MOBILE_ID=?
Hibernate: update MOBILE_NUM set USER_ID=? where MOBILE_ID=?
Hibernate: select user_detai0_.USER_ID as USER_ID1_1_0_, user_detai0_.First_Name as First_Name2_1_0_, user_detai0_.Last_Name as Last_Name3_1_0_ from USER_DETAILS user_detai0_ where user_detai0_.USER_ID=?
Retrieving the saved objects
First User
User Id : 1
First Name : First
Last Name : User
Hibernate: select mob0_.USER_ID as USER_ID3_0_0_, mob0_.MOBILE_ID as MOBILE_ID1_0_0_, mob0_.MOBILE_ID as MOBILE_ID1_0_1_, mob0_.mobile_number as mobile_number2_0_1_ from MOBILE_NUM mob0_ where mob0_.USER_ID=?
Mobile id : 1
Mobile number : 1111111
Mobile id : 2
Mobile number : 2222222
This output shows you all the SQL commands executed by the Hibernate within the database to map the Java class to a database table and perform all the
activities of saving and retrieving the objects of both Entity classes involved in a one-to-one relationship.
Moreover, if you see the following SQL query in the database -
select * from USER_DETAILS;
you will get the following output displaying the objects of User_Details Entity class stored in USER_DETAILS table, as shown below.
And on executing the second query in the database -
select * from MOBILE_NUM;
you will get the following output displaying the objects of child Mobile_Num class stored in MOBILE_NUM table, as shown below, as shown below.
This table shows you how our first user(having id =1), is associated with multiple mobiles(each having different ids)
This output shows how each object of User_Details class is involved in a one-to-many relationship with objects of Mobile_Num.
Note :
If you wish to create a new table showing one-to-many relationship between two classes then instead of @JoinColumn in primary class,
you will have to use @JoinTable annotation.
The output clearly shows you that Hibernate has used its sequence object to generate the value of each primary key(Id) automatically as we have used @GeneratedValue
annotations with it.