This article is about hibernate inheritance. Here we will be disussing about the different inheritance strategy supported by hibernate such as Single Table Strategy, Table per class strategy and Joined strategy along with their advantages and disadvantages. We will be creating code samples for each strategy and discuss about their behaviour in a great detail.
Background
As we know Java is an object oriented language and hence it supports inheritance. In java inheritance, there can be IS-A or HAS-A relationship. But when we come to any relational model, it supports only HAS-A relationship. To overcome this mimmatch hibernate provides different inheritance strategy. There are basically 3 types of hibernate strategy as follows.
1. Single Table Strategy
2. Table Per Class Strategy
3. Joined Table Strategy
Now let us discuss about these 3 strategies one by one. In the examples below, we have 3 different entities. The parent entity Employee.java
is being extended by 2 other entities PermanentEmployee.java
and ContractEmployee.java
Hibernate Single Table Strategy
In case of single table strategy, there is a single table created per inheritance hierachy. For example, we have Employee class being extended by 2 others classes but when it comes to single table strategy a single table will be created representing all the classes per inheritance hieracy and this table will contain all the data related to either Employee or ContractEmployee or PermanentEmployee.
So, the question arises as if all the entries are made in a single table then how can we identify those rows from object perspective. For this, hbernate provides a Discriminator Type(DType) column which helps to differentiate between these records. This configuration is completely annotation based. So let us define our entities and implement hibernate inheritance with Single Table Strategy.
Other Interesting Posts Spring Hibernate Integration Example with JavaConfig Object Relational Mapping in Java Hibernate Different Annotations Example Hibernate One to Many Mapping Example Hibernate One to Many Relationship Example Hibernate Many to Many Relationship ExampleEmployee.java
@Entity @Table(name = "EMPLOYEE") @Inheritance(strategy=InheritanceType.SINGLE_TABLE) public class Employee { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "EMP_ID") private int empId; @Column(name ="name") private String name;PermanentEmployee.java
@Entity @Table(name="PERMANENT_EMPLOYEE") @DiscriminatorValue("PERMANENT_EMP") public class PermanentEmployee extends Employee { @Column(name="TYPE") private String type;ContractEmployee.java
@Entity @Table(name="CONTRACT_EMPLOYEE") @DiscriminatorValue("CONTRACT_EMP") public class ContractEmployee extends Employee { @Column(name="TYPE") private String type;
@Inheritance - It is used to define the type of inheritance used in hibernate and it is defined in the parent class. If the Inheritance annotation is not specified or if no inheritance type is specified for an entity class hierarchy, the SINGLE_TABLE mapping strategy is used.
@DiscriminatorValue - This annotation is used to specify the DType column name. Here we have defined it as PERMANENT_EMP
in case of PermanentEmployee.java
and CONTRACT_EMPLOYEE
in case of ContractEmployee.java
. The DiscriminatorValue annotation can only be specified on a concrete entity class. If the DiscriminatorType is STRING, the discriminator value default is the entity name.
Defining hibernate.cfg.xml
<hibernate-configuration> <session-factory> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost/test</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property> <property name="hibernate.hbm2ddl.auto">update</property> <property name="show_sql">false</property> <mapping class="com.devglan.model.Employee"/> <mapping class="com.devglan.model.ContractEmployee"/> <mapping class="com.devglan.model.PermanentEmployee"/> </session-factory> </hibernate-configuration>
Testing Single Table Strategy
Let us define Application.java having a main method inside it to run the example and see the entries it created in the DB
Application.javapublic class Application { public static void main(String[] args) { createEmployee(); } public static SessionFactory getSessionFactory() { Configuration configuration = new Configuration().configure(); StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder() .applySettings(configuration.getProperties()); SessionFactory sessionFactory = configuration .buildSessionFactory(builder.build()); return sessionFactory; } public static void createEmployee() { System.out.println("****************Creating Employee*************"); Employee emp = new Employee(); emp.setName("John"); ContractEmployee contEmp = new ContractEmployee(); contEmp.setName("Mike"); contEmp.setType("CONTRACT"); PermanentEmployee perEmp = new PermanentEmployee(); perEmp.setName("Jordan"); perEmp.setType("PERMANENT"); Session session = getSessionFactory().openSession(); session.beginTransaction(); session.save(emp); session.save(contEmp); session.save(perEmp); session.getTransaction().commit(); session.close(); } }
If you run above class a java application, then you can see entries created in the DB. Since, we did not define any specific value for DTYPE column in Employee.java, by default hibernate named it as entity class name.
Advantages of Single Table Strategy
Simplest to implement.
Only one table to deal with.
Performance wise better than all strategies because no joins or sub-selects need to be performed.
Disadvantages of Single Table Strategy
Most of the column of table are nullable so the NOT NULL constraint cannot be applied.
Tables are not normalized.
Hibernate Table Per Class Strategy
In case of table per class strategy, there are no. of tables created equivalent to exact no. of concrete entites defined in the inheritance hierachy. Hence, in our case there will be 3 different table created and each child table contains duplicate data of its parent. Hence, this strategy is not recommended. Let us redefine the same entities to accomodate table per class strategy.
Employee.java@Entity @Table(name = "EMPLOYEE") @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public class Employee { @Id @GeneratedValue(strategy = GenerationType.TABLE) @Column(name = "EMP_ID") private int empId; @Column(name ="name") private String name;ContractEmployee.java
@Entity @Table(name="CONTRACT_EMPLOYEE") public class ContractEmployee extends Employee { @Column(name="TYPE") private String type;PermanentEmployee.java
@Entity @Table(name="PERMANENT_EMPLOYEE") public class PermanentEmployee extends Employee { @Column(name="TYPE") private String type; }
In this case there no need for the discriminator column because all entity has own table. In this strategy you use one table per class and each one has an ID. Hence, the generation type auto does not work here.
Testing Table Per Class Strategy
The Application.java remains unchanged. Run this class as a java application and check the entries created in DB as per table per class strategy.
Advantages of Table Per Class Strategy
You can define NOT NULL constraints on the table.
Disadvantages of Table Per Class Strategy
Tables are not normalized.
Select statements require more time to execute as UNION operation is applied.
Hibernate Joined Table Strategy
In this strategy, all the entries in the DB will be created in one table that is corresponding table of parent entity and the tables corresponding to the child entities will have reference to it. If this confuses you, then let us define our entities first and see the DB structure quickly to understand better.
Employee.java@Entity @Table(name = "EMPLOYEE") @Inheritance(strategy=InheritanceType.SINGLE_TABLE) public class Employee { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "EMP_ID") private int empId; @Column(name ="name") private String name;ContractEmployee.java
@Entity @Table(name="CONTRACT_EMPLOYEE") @DiscriminatorValue("CONTRACT_EMP") public class ContractEmployee extends Employee { @Column(name="TYPE") private String type;PermanentEmployee.java
@Entity @Table(name="PERMANENT_EMPLOYEE") @DiscriminatorValue("PERMANENT_EMP") public class PermanentEmployee extends Employee { @Column(name="TYPE") private String type;
The only change in the entity definition here is the type of strategy defined in Employee.java
Testing Joined Table Strategy
The Application.java remains unchanged. Run this class as a java application and check the entries created in DB.
Advantages of Joined Table Strategy
Tables are normalized.
You can define NOT NULL constraints.
Disadvantages of Joined Table Strategy
Low performance as it runs OUTER JOIN as well as INNER JOIN in select stements.
Conclusion
I hope this article served you whatever you were looking for. If you have anything that you want to add or share then please share it below in the comment section.