In our last article, we have explained you how to perform a many-to-many mapping of objects between two Entity classes using Hibernate annotations.
Today we are going to understand how to perform a many-to-many mapping of objects between two Entity classes
using Hibernate's mapping resource file, instead of using its annotations.
A many-to-many relationship is all about how multiple objects of one class are associated with multiple objects of another class.
To understand many-to-many mapping, let's take an example of two Entity classes - User_Details and Mobile_Num,
where the objects of both Entity classes are stored in separated database tables and multiple objects User_Details are having an association with multiples objects of Mobile_Num class.
So, each
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;
import java.util.ArrayList;
import java.util.List;
public class Mobile_Num
{
private int id;
private int mobile_number;
private List<User_Details> userCollection = new ArrayList<User_Details>();
public List<User_Details> getUserCollection() {
return userCollection;
}
public void setUserCollection(List<User_Details> userCollection)
{
this.userCollection = userCollection;
}
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 and Mobile_Num objects, which will be persisted using the Hibernate API and an
object-relational mapping(ORM) in the database is performed displaying many-to-many relation.
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 Hiber
{
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_Details user1 = new User_Details();
user1.setFirstName("First");
user1.setLastName("User");
//Creating the second User details
User_Details user2 = new User_Details();
user2.setFirstName("Second");
user2.setLastName("User");
//Adding the users to a collection
List userCollection = new ArrayList();
userCollection.add(user1);
userCollection.add(user2);
//Creating the contact info for the user
Mobile_Num mob1 = new Mobile_Num();
mob1.setMobile_number(1111111);
//Setting the collection of user to the first mobile
mob1.setUserCollection(userCollection);
//Creating the contact info for the user
Mobile_Num mob2 = new Mobile_Num();
mob2.setMobile_number(2222222);
//Setting the collection of user to the second mobile
mob2.setUserCollection(userCollection);
List<Mobile_Num> mobileCollection = new ArrayList<Mobile_Num>();
mobileCollection.add(mob1);
mobileCollection.add(mob2);
//Setting the collection of mobiles to a user
user1.setMob(mobileCollection);
user2.setMob(mobileCollection);
//Saving the first User_Details object in database and its associated
//mobile information is automatically saved plus the second user associated with it.
session.beginTransaction();
session.save(user1);
session.getTransaction().commit();
session.close();
//Retrieve and displaying the user details
session = sf.openSession();
session.beginTransaction();
user1 = (User_Details)session.get(User_Details.class,1);
System.out.println("Retrieving the saved objects");
mobileCollection = (List<Mobile_Num>) user1.getMob();
mob1 = mobileCollection.get(0);
//Accessing the user from the first mobile object to display mobile's association with the user and bidirectional cccess many-to-many mapping
user1 = mob1.getUserCollection().get(0);
System.out.println("Information about the user of mobile1");
System.out.println("User Id : " + mob1.getId());
System.out.println("First Name : " + user1.getFirstName());
System.out.println("Last Name : " + user1.getLastName());
System.out.println("Mobile id : " + mob1.getId());
System.out.println("Mobile number : " + mob1.getMobile_number());
//Accessing the user from the second mobile object to display mobile's association with the user and bidirectional access and many-to-many mapping
user2 = mob1.getUserCollection().get(1);
System.out.println("Information about the user of mobile2 ");
System.out.println("User Id : " + mob2.getId());
System.out.println("First Name : " + user1.getFirstName());
System.out.println("Last Name : " + user1.getLastName());
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"/>
<bag name ="mob" table="USER_MOBILE" cascade="all" fetch="select">
<key column="USER_ID"/>
>many-to-many column="MOBILE_ID" class="decodejava.Mobile_Num"/>
</bag>
</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">
<param name="property">id</param>
</generator>
</id>
<property name = "mobile_number" column = "Mobile_Number" type = "int"/>
<bag name ="userCollection" table="USER_MOBILE" fetch="select" cascade="all" inverse="true">
<key column="MOBILE_ID"/>
<many-to-many column="USER_ID" class="decodejava.User_Details"/>
</bag>
</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 bag element maps a collection object of type List to a database table and without adding index like list element does.
the name child attribute refers to the name of a Collection property in the class involved in a many-to-many relation.
the table child attribute refers to the name of the table that will to hold 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 inverse child attribute specifies whethere a collection is a part of a bidirectional 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 <many-to-many> element maps a many-to-many relationship between the object of two classes, i.e.
how multiple objects of one class are associated with multiple objects of another class.
The column child attribute refers name of the foreign key column in this many-to-one relationship.
The class child attribute refers name of the class which is part of this many-to-one relationship.
Directory Structure of Hibernate Project
The picture above depicts how and where to arrange the primary POJO/Entity(.java) file, the secondary Entity(.java) file and the other the class(that calls the hibernate into action)
in a specific directory structure.
Project Folder - HibernateManyToManyMapping 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 primary 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
as we have used some Hibernate Annotations in this project, hence, there will be no need to create the mapping-resource
with extension 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, three 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.
USER_MOBILE, representing the many-to-many relation between USER_DETAILS and MOBILE_NUM tables( i.e. between the objects of User_Details
and Mobile_Num class).
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, 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: create table USER_MOBILE (USER_ID number(10,0) not null, MOBILE_ID number(10,0) not null)
Hibernate: alter table USER_MOBILE add constraint FKickarewyyl0ipc9fbkpjo72oy foreign key (MOBILE_ID) references USER_DETAILS
Hibernate: alter table USER_MOBILE add constraint FKn1ond2ybbavshwgllksuba4d1 foreign key (USER_ID) references MOBILE_NUM
May 24, 2018 12:47:00 PM org.hibernate.tool.schema.internal.SchemaCreatorImpl applyImportSources
INFO: HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@60dce7ea'
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: select id_seq.nextval from dual
Hibernate: select id_seq.nextval from dual
Hibernate: select hibernate_sequence.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 USER_DETAILS (First_Name, Last_Name, USER_ID) values (?, ?, ?)
Hibernate: insert into MOBILE_NUM (mobile_number, MOBILE_ID) values (?, ?)
Hibernate: insert into USER_MOBILE (USER_ID, MOBILE_ID) values (?, ?)
Hibernate: insert into USER_MOBILE (USER_ID, MOBILE_ID) values (?, ?)
Hibernate: insert into USER_MOBILE (USER_ID, MOBILE_ID) values (?, ?)
Hibernate: insert into USER_MOBILE (USER_ID, MOBILE_ID) values (?, ?)
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 the objects of both Entity classes involved in a many-to-many 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 Mobile_Num class stored in MOBILE_NUM table, as shown below, as shown below.
And, on executing the third query in the database -
select * from USER_MOBILE;
This table shows you many-to-many mapping between two tables as shown below.
This table shows you how our each user, is associated with multiple mobiles(each having different ids) and how each mobile is associated with
multiple users, displaying the many-to-many relationship between the objects of User_Details and Mobile_Num classes.
Note :
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.