Today we are going to understand how to map inheritance between the classes to the database with Hibernate using the mapping resource xml file(without using Annotation).
As you already know, inheritance is used when a class wants to use/inherit the
features of another existing class.
The class that wants to use the feature of another class, is called subclass,
whereas the class whose features are to be used/inherited is referred to as superclass.
A class inheriting from another class, can access its features and can also add its own specific features.
Let's take an example of an Entity class - Country, which is extended by two classes AsianCountry and EurpoeanCountry.
By default, Hibernate performs the inheritance between classes by combining all of their objects under single table and this strategy is also called Single Table Strategy.
Now, let's see how Hibernate performs object-relational-mapping(ORM) to represent the inheritance between these three classes in the database.
Note :
In the upcoming example, We are going to create a Java class which will be mapped to a table 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/parent Entity class
We are going to create a general parent class that will contain all the Java code files
representing our Model class(whose objects needs to be persisted). This parent class will be inherited by a few child classes that we are going to create later on.
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.
Country.java
package decodejava;
public class Country
{
private int id;
private String name;
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
Advertisement
Creating the first child Entity class
Next, we are going to create the child Entity class inheriting from the parent Country class. The object of this child class will also be persisted in the database table.
The object of this class will contain a few specific properties such as continent and population to save these specifics about each country.
This class is also an entity class.
AsianCountry.java
package decodejava;
public class AsianCountry extends Country {
private String continent;
private int population;
public String getContinent() {
return continent;
}
public void setContinent(String continent)
{
this.continent = continent;
}
public int getPopulation()
{
return population;
}
public void setPopulation(int population)
{
this.population = population;
}
}
Creating the second child Entity class
Next, we are going to create another child Entity class inheriting from the parent Country class.
The object of this child class will also be persisted in the database table.
The object of this class will also contain a few specific properties to capture information about each country, such as its continent and population.
This class is also an entity class.
EuropeanCountry.java
package decodejava;
public class EuropeanCountry extends Country
{
private String continent;
private int population;
public String getContinent()
{
return continent;
}
public void setContinent(String continent)
{
this.continent = continent;
}
public int getPopulation()
{
return population;
}
public void setPopulation(int population)
{
this.population = population;
}
}
Creating the class that calls the Hibernate API - Utility class
This class will create objects of all the three classes(parent and its subclasses) involved in inheritance, 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 org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Hiber {
public static void main(String[] args)
{
Configuration config = new Configuration();
SessionFactory sf = config.configure().buildSessionFactory();
Session session = sf.openSession();
Country country1 = new Country();
country1.setName("Asian Country");
AsianCountry asianCountry1 = new AsianCountry();
asianCountry1.setName("Japan");
asianCountry1.setContinent("Asia");
asianCountry1.setPopulation(127000000);
EuropeanCountry europeanCountry1 = new EuropeanCountry();
europeanCountry1.setName("Germany");
europeanCountry1.setContinent("Europe");
europeanCountry1.setPopulation(87000000);
session.beginTransaction();
session.save(country1); //Saving the first Country object object
session.save(asianCountry1); //Saving the first AsianCountry object
session.save(europeanCountry1); //Saving the first EuropeanCountry object
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 within our package decodejava.
This file allows Hibernate to map the Model/Entity class and Value Type class to a table in the database and perform the object-relational mapping.
This mapping document ends with an extension .hbm.xml, hence, we have named it country.hbm.xml.
This mapping document ends with an extension .hbm.xml,
hence, we have named it employeedetails.hbm.xml.
This mapping document tells Hibernate -
The name of the class to be mapped to a database table.
The name of the database table to be created.
The specific field, which is to be made the primary key in this table.
The data-type of each property in the class, which is going to mapped to a column in a table.
country.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.Country" table = "COUNTRY" discriminator-value="Country">
<id name = "id" column = "COUNTRY_ID" type = "int">
<generator class="native"/>
</id>
<discriminator column ="CLASS_TYPE" type="string"/>
<property name = "name" column = "Country_Name" type = "string"/>
<subclass name="decodejava.AsianCountry" discriminator-value="AsianCountry">
<property name = "continent" column = "CONTINENT" type = "string"/>
<property name = "population" column = "POPULATION" type = "int"/>
</subclass>
<subclass name="decodejava.EuropeanCountry" discriminator-value="EuropeanCountry">
<property name = "continent" column = "CONTINENT" type = "string"/>
<property name = "population" column = "POPULATION" type = "int"/>
</subclass>
</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 discriminator-value attribute which defines a specific value to be placed for each object of a specific Entity class
in discriminator column(explained next).
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.
To differentiate between the three Entity classes, we have added a discriminator child element which allows us to
add a column to the table and contains a discriminator-value for each object type.
The subclass element maps a subclass of an Entity parent class.
the name child attribute refers to the name of the subclass.
The discriminator-value attribute which defines a specific value to be placed for each object of this subclass in discriminator column.
The name property of subclass element refers to the name of a property in the subclass.
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 the parent and subclasses to a database table.
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">system</property>
<property name="connection.password">promila21</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>
<!-- Names the mapping entity class -->
<mapping class ="decodejava.Country"/>
<mapping class ="decodejava.AsianCountry"/>
<mapping class ="decodejava.EuropeanCountry"/>
</session-factory>
</hibernate-configuration>
Directory Structure of Hibernate Project
The picture above depicts how and where to arrange POJO/Entity(.java) file, its two child Entity classes and the class(that calls the hibernate into action)
in a specific directory structure.
Project Folder - HibernateSingleTableInheritance 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 POJO/Entity class file i.e. Country.java, its first child class i.e. AsianCountry.java, second child class i.e.
EuropeanCountry.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
named country.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
When you execute the Hiber.java class, you will see the following output -
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate: create table Country (DTYPE varchar2(31 char) not null, id number(10,0) not null, name varchar2(255 char), continent varchar2(255 char), population number(10,0), primary key (id))
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: insert into Country (name, DTYPE, id) values (?, 'Country', ?)
Hibernate: insert into Country (name, continent, population, DTYPE, id) values (?, ?, ?, 'AsianCountry', ?)
Hibernate: insert into Country (name, continent, population, DTYPE, id) values (?, ?, ?, 'EuropeanCountry', ?)
This output shows you all the SQL commands executed by the Hibernate within the database to map the inheritance between the Java classes
to a database table and perform all the
activities of saving the objects of all three Entity classes.
Finally, after executing Hiber class a new table will be constructed -
Country, representing the inheritance between the three classes in the database.
Moreover, if you type the following SQL query in the database -
select * from Country;
you will get the following output displaying -
The objects of the parent Country Entity class.
The objects of child AsianCountry Entity class.
The objects of another child EuropeanCountry Entity class.
This table shows you how hibernate adds all the objects of classes involved in inheritance relationship, within a single database table,
where CLASS_TYPE column shows you the class name of each object.