In our last article, we performed mapped inheritance between the classes to database using Hibernate's table per class strategy with annotations. In this article,
we are going to show you how to perform inheritance using Hibernate's table per class strategy by
using mapping resource file, instead of using annotations.
As the name says, table per class strategy allows us to performing inheritance using Hibernate that will create different tables created for each class
involved in the inheritance. i.e. a separate table for parent class and a separate table for each of its child classes, with each child class
inheriting the properties from the parent class.
Let's take the same example of an Entity class - Country, which is extended/inherited by two classes AsianCountry and EurpoeanCountry.
Now, let's see how Hibernate performs object-relational-mapping(ORM) to represent the inheritance between these three classes in the database, by using table per class strategy.
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 a separate 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 a separate 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">
<id name = "id" column = "COUNTRY_ID" type = "int">
<generator class="native"/>
</id>
<property name = "name" column = "Country_Name" type = "string"/>
</class>
<class name="decodejava.AsianCountry" table="AsianCountry">
<id name = "id" column = "COUNTRY_ID" type = "int">
<generator class="native"/>
</id>
<property name = "continent" column = "CONTINENT" type = "string"/>
<property name = "population" column = "POPULATION" type = "int"/>
</class>
<class name="decodejava.EuropeanCountry" table="EuropeanCountry">
<id name = "id" column = "COUNTRY_ID" type = "int">
<generator class="native"/>
</id>
<property name = "continent" column = "CONTINENT" type = "string"/>
<property name = "population" column = "POPULATION" 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 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.
The class-name element maps a subclass of an Entity parent class to its own database table.
The name child attribute refers to the name of the subclass.
The table child attribute refers to the name of database table mapping the subclass.
The id element maps a property within the class to the primary key of the database table.
The name property of subclass element refers to the name of a property in the subclass.
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.
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>
<!--Naming the mapping resource file -->
<mapping resource="country.hbm.xml"/>
</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 - HibernateTablePerClassInheritance 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 Asian_Country (id number(10,0) not null, name varchar2(255 char), continent varchar2(255 char), population number(10,0) not null, primary key (id))
Hibernate: create table Country (id number(10,0) not null, name varchar2(255 char), primary key (id))
Hibernate: create table European_Country (id number(10,0) not null, name varchar2(255 char), continent varchar2(255 char), population number(10,0) not null, 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, id) values (?, ?)
Hibernate: insert into Asian_Country (name, continent, population, id) values (?, ?, ?, ?)
Hibernate: insert into European_Country (name, continent, population, id) values (?, ?, ?, ?)
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 separate database table for each class and perform all the
activities of creating the tables and saving the objects of all three Entity classes.
Finally, after executing Hiber class, three separate tables will be created in the database -
Country, representing object-relational mapping(ORM) for Country class.
Asian_Country, representing object-relational mapping(ORM) for AsianCountry class.
European_Country, representing object-relational mapping(ORM) for EuropeanCountry class.
Next, let's query the database and see what are the contents of these tables -
select * from Country;
This table shows you the object of parent class Country represented by Country, as shown above.
select * from Asian_Country;
This table shows you the object of child class AsianCountry and the properties such as id and name it has inherited from its parent class Country, as shown above.
select * from European_Country;
This table shows you the object of child class EuropeanCountry and the properties such as id and name it has inherited from its parent class Country, as shown above.
In the upcoming articles, we are going to look at the third strategy used by Hibernate to implement inheritance between classes, known as - Joined.