Welcome to Hibernate Tutorial Series. In previous tutorials we saw how to implement Relationship Mapping in Hibernate. We saw different mapping techniques like One to Many, Many to Many using both Annotations and XML mapping.
Today we will see how the Inheritance is managed in Hibernate.
Introduction to Inheritance in Hibernate
Java is an object oriented language. It is possible to implement Inheritance in Java. Inheritance is one of the most visible facets of Object-relational mismatch. Object oriented systems can model both “is a” and “has a” relationship. Relational model supports only “has a” relationship between two entities. Hibernate can help you map such Objects with relational tables. But you need to choose certain mapping strategy based on your needs.
One Table Per Class Hierarchy example
Suppose we have a class Person with subclass Employee. The properties of each class are:
* class Person - firstname - lastname * class Employee - joining_date - department_name
In One Table per Class Hierarchy scheme, we store all the class hierarchy in a single SQL table. A discriminator is a key to uniquely identify the base type of the class hierarchy.
Following are the advantages and disadvantages of One Table per Class Hierarchy scheme.
Advantage
This hierarchy offers the best performance even for in the deep hierarchy since single select may suffice.
Disadvantage
Changes to members of the hierarchy require column to be altered, added or removed from the table.
Create Database Table to persist Class Hierarchy
CREATE TABLE `person` (
`person_id` BIGINT(10) NOT NULL AUTO_INCREMENT,
`firstname` VARCHAR(50) NULL DEFAULT NULL,
`lastname` VARCHAR(50) NULL DEFAULT NULL,
`joining_date` DATE NULL DEFAULT NULL,
`department_name` VARCHAR(50) NULL DEFAULT NULL,
`discriminator` VARCHAR(20) NOT NULL,
PRIMARY KEY (`person_id`)
)
Code language: SQL (Structured Query Language) (sql)
The PERSON
table will store both Employee
and Person
objects.
Hibernate Inheritance: XML Mapping
Following is the example where we map Employee and Person entity classes using XML mapping.
File: Person.java
package net.viralpatel.hibernate;
public class Person {
private Long personId;
private String firstname;
private String lastname;
// Constructors and Getter/Setter methods,
}
Code language: Java (java)
File: Employee.java
package net.viralpatel.hibernate;
import java.util.Date;
public class Employee extends Person {
private Date joiningDate;
private String departmentName;
// Constructors and Getter/Setter methods,
}
Code language: Java (java)
File: Person.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="net.viralpatel.hibernate">
<class name="Person" table="PERSON" discriminator-value="P">
<id name="personId" column="PERSON_ID">
<generator class="native" />
</id>
<discriminator column="DISCRIMINATOR" type="string" />
<property name="firstname" />
<property name="lastname" column="lastname" />
<subclass name="Employee" extends="Person" discriminator-value="E">
<property name="departmentName" column="department_name" />
<property name="joiningDate" type="date" column="joining_date" />
</subclass>
</class>
</hibernate-mapping>
Code language: HTML, XML (xml)
Note that we have defined only one hibernate mapping (hbm) file Person.hbm.xml
. Both Person
and Employee
model class are defined within one hbm file.
<discriminator> tag is used to define the discriminator column.
<subclass> tag is used to map the subclass Employee. Note that we have not used the usual <class>
tag to map Employee as it falls below in the hierarchy tree.
The discriminator-value for Person
is defined as “P” and that for Employee
is defined “E”, Thus, when Hibernate will persist the data for person or employee it will accordingly populate this value.
Hibernate Inheritance: Annotation Mapping
Following is the example where we map Employee and Person entity classes using JPA Annotations.
File: Person.java
package net.viralpatel.hibernate;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
@Entity
@Table(name = "PERSON")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
name="discriminator",
discriminatorType=DiscriminatorType.STRING
)
@DiscriminatorValue(value="P")
public class Person {
@Id
@GeneratedValue
@Column(name = "PERSON_ID")
private Long personId;
@Column(name = "FIRSTNAME")
private String firstname;
@Column(name = "LASTNAME")
private String lastname;
// Constructors and Getter/Setter methods,
}
Code language: Java (java)
The Person
class is the root of hierarchy. Hence we have used some annotations to make it as the root.
@Inheritance
– Defines the inheritance strategy to be used for an entity class hierarchy. It is specified on the entity class that is the root of the entity class hierarchy.
@DiscriminatorColumn
– Is used to define the discriminator column for the SINGLE_TABLE and JOINED inheritance mapping strategies. The strategy and the discriminator column are only specified in the root of an entity class hierarchy or sub hierarchy in which a different inheritance strategy is applied
If the @DiscriminatorColumn
annotation is missing, and a discriminator column is required, the name of the discriminator column defaults to "DTYPE"
and the discriminator type to DiscriminatorType.STRING
.
@DiscriminatorValue
– Is used to specify the value of the discriminator column for entities of the given type. The DiscriminatorValue
annotation can only be specified on a concrete entity class. If the DiscriminatorValue annotation is not specified and a discriminator column is used, a provider-specific function will be used to generate a value representing the entity type. If the DiscriminatorType is STRING, the discriminator value default is the entity name.
The inheritance strategy and the discriminator column are only specified in the root of an entity class hierarchy or subhierarchy in which a different inheritance strategy is applied. The discriminator value, if not defaulted, should be specified for each entity class in the hierarchy.
File: Employee.java
package net.viralpatel.hibernate;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Table;
@Entity
@Table(name="PERSON")
@DiscriminatorValue("E")
public class Employee extends Person {
@Column(name="joining_date")
private Date joiningDate;
@Column(name="department_name")
private String departmentName;
// Constructors and Getter/Setter methods,
}
Code language: Java (java)
Employee class is child of Person class. Thus while specifying the mappings, we used @DiscriminatorValue
to specify discriminator value. In our case “E” will be persisted in discriminator column.
Main class
package net.viralpatel.hibernate;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
public class Main {
public static void main(String[] args) {
SessionFactory sf = HibernateUtil.getSessionFactory();
Session session = sf.openSession();
session.beginTransaction();
Person person = new Person("Steve", "Balmer");
session.save(person);
Employee employee = new Employee("James", "Gosling", "Marketing", new Date());
session.save(employee);
session.getTransaction().commit();
session.close();
}
}
Code language: Java (java)
The Main class is used to persist Person
and Employee
object instance. Note that both these classes are persisted in same table PERSON
. The discriminator column is used to distinguished between the entities.
Output
Hibernate: insert into EMPLOYEE (FIRSTNAME, LASTNAME, discriminator) values (?, ?, 'P')
Hibernate: insert into EMPLOYEE (FIRSTNAME, LASTNAME, department_name, joining_date, discriminator) values (?, ?, ?, ?, 'E')
Code language: SQL (Structured Query Language) (sql)
Download Source Code
Hibernate-inheritance-table-per-heirarchy_xml.zip (8 KB)
Hibernate-inheritance-table-per-heirarchy_annotation.zip (8 KB)
Hi Viral
I have some queries related to this tutorial
In thease classes you have created constructors and setter and getter methods
where as in most hibernate tutorials i have seen .java files as simple POJO classes only…
then why you have created the constructors for these classes??
Hi Viral,
Its really a nice article. I can see in every site about the xml mapping and how to store the hierarchy in the tables but none about ways to retrieve the hierarchy..
Person P =session.uniqueResult()..;
Can we type case it to Emploee e= (Employee) P;
can you give some information on these please
In Person.hbm.xml the following line
was found to be as
When I extracted it from Hibernate-inheritance-table-per-heirarchy_xml.
Hi Viral,
I generated my hibernate XML mappings(hbm.xmls) using Hibernate tool’s reverse engg approach. It generated me three hbms for 3 tables in db.
Is it possible to achieve inheritance as shown by you using tool… ?
I am using annotations and I have a class called Territory. A territory has two attributes: Its assigned salesman and a geographical area. This can be a region, a country, or a US state, all of which are separate classes that share a common parent AbstractGeographicalArea.
When Hibernate instantiates Territory, I want it to determine what subclass of AbstractGeographicalArea it is and instantiate that.
In my Territory table, I am going to have a column for the ID of the particular area be it a region, country, or state. Therefore, theoretically, the values in that column could be non-unique. A value of 1 could be the ID for Japan, Europe, or California. How do I tell Hibernate which class is to be used?
I thought I’d found the solution by using the @Any annotation and setting up a metacolumn, but I don’t see a way to tie that to the column containing the ID. It complains that AbstractGeographicalArea is an unknown entity.
@OneToOne (cascade=CascadeType.ALL)
@JoinColumn(name=”FK_PLACE”, unique= false, nullable=false, insertable=true, updatable=true)
private AbstractGeographicalArea place;
@Any(metaColumn = @Column(name = “PLACE_CLASS”))
@AnyMetaDef(idType = “long”, metaType = “string”, metaValues = {
@MetaValue(targetEntity = Country.class, value = Country.CLASS_CODE),
@MetaValue(targetEntity = State.class, value = State.CLASS_CODE) })
@JoinColumn(name = “FK_PLACE”)
private String placeClass;
I don’t want everything crammed into one table because I am going to draw reports off this database and I think that would make reporting more difficult. Any ideas would be appreciated.
Very good example, very clear.
Thanks
Thank you very much for your very usefull tutorials!
thak you so much buddy for this tutorial :):)
Good example, thanks much.
very good example for beginners..tnx..
Very nice example.. got clarity..Thanks for the post
Hi Viral, Does Hibernate Reverse Engineering allow generating two entities for one table? If yes, how do I configure it?
nice
Thanku sooooo much…..very clear explanation.
i am gertting below erro. please advise
Initial SessionFactory creation failed.java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/validation/Validation
Exception in thread “main” java.lang.ExceptionInInitializerError
at net.viralpatel.hibernate.HibernateUtil.buildSessionFactory(HibernateUtil.java:18)
at net.viralpatel.hibernate.HibernateUtil.(HibernateUtil.java:8)
at net.viralpatel.hibernate.Main.main(Main.java:12)
Caused by: java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/validation/Validation
at java.lang.ClassLoader.defineClass1(Native Method)
What happens when I want to change the type of the class in the hierarchy?
example:
initial situation: Person person1 = new Person(); //and fill in all fields
then: Person personChanged = new Employee(); //copy all fields from person1 to personChanged.
That’s a kind of situation where a person becomes an employee and the status needs to be changed. However with the code in this tutorial, when you “merge” (update) the personChanged (same ID and fields + new field values) Hibernate will NOT update person1 but INSERT personChanged. This is not usually what you want when modeling such inheritance, right?
Its a very nicely written article, here are some more disadvantages of using single table –
1- The table is not normalized and hence the sql optimization will not work on it.
2- For cases where the program already knows- if its an employee or not , it still needs to search in list of all the people, so it will be slow performance wise.
3- Additional if condition in all the queries.
Nice example quite crisp and clear upto the point thnks a ton
Excellent and easy to follow post.
Hi, very nice example.
Thanks a lot!!!
Thanks
Nice article….
Thanks for your efforts…
the information is incomplete. it talks only abt DATA insertion and about retrival which is way more tricky
Thanks Viral for this tutorial, it was really helpful.
Excellent Articles on Hibernate Inheritance. Thanks Virat ..!
Hi patel, nice tutorials, just 1 question , why is there @Table(name=”PERSON”) over Employee, as only person table is created in the d-base.
Hi Viral,
You said that the only and unique table created in the database is “PERSON’.
How come that in the Output you have:
“Hibernate: insert into EMPLOYEE (FIRSTNAME, LASTNAME, discriminator) values (?, ?, ‘P’)
Hibernate: insert into EMPLOYEE (FIRSTNAME, LASTNAME, department_name, joining_date, discriminator) values (?, ?, ?, ?, ‘E’)”
with “insert into EMPLOYEE”?
I thought that the table’s name was “PERSON”, so why do you have the table “EMPLOYEE”?
Excellent Article, Very easy understanding way about the classes persist in a table using inheritance :-) Thank you very much
Hey Viral, this is so far the best example I have found about Hibernate inheritance that actually uses to a “real life” case and not implying generic abstract cases (like Class Animal, Class Snake extends Animal etc…that only really explain Java subclasses rather than Hibernate inheritance). Thank you for the great article!
Fred
Great article
Thank you. This really helped me understand how discriminator values need to be used.