Open In App

Hibernate – Table Per Hierarchy using Annotation

Last Updated : 13 Jun, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

Hibernate is a framework that provides some abstraction layer, meaning that the programmer does not have to worry about the implementations, it does the implementations for you internally like writing queries to perform CRUD operations, establishing a connection with the database, etc. It is an open-source, non-invasive, lightweight java ORM(Object-relational mapping) framework that is used to develop persistence logic that is independent of Database software.

Hibernate is capable of storing the inherited properties of an object along with its new properties in its database when an object is saved in the database. In Hibernate, inheritance between POJO classes is applied when multiple POJO classes of a module contain some common properties. 

Hibernate Inheritance Mapping

Object-oriented can model both “is a” and “has a” relationship. The relational model supports only the “has a” relationship between two entities. Hibernate helps in mapping such Objects with relational tables. There are three inheritance mapping strategies defined in the Hibernate.

  • Table Per Hierarchy
  • Table Per Concrete class
  • Table Per Subclass

Table Per Hierarchy (Using Annotations)

Table per Hierarchy is one of the inheritance strategies in hibernate. In this strategy, the entire hierarchy is mapped to a single table. All attributes of all the classes in the hierarchy are stored in a single table.

In a table per Hierarchy strategy :

  • Only one table is created in the database for storing data of the entire class hierarchy.
  • Hibernate needs an additional column in the table called a discriminator column for placing or storing the discriminator value of a subclass object.
  • The discriminator column is mandatory while it is optional in the other two mapping strategies mentioned above.

A discriminator uniquely identifies the base type of the class hierarchy.

Important Annotations

Annotation 1: @Inheritance 

This annotation 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. If the @Inheritance annotation is not specified or if no inheritance is specified for an entity class hierarchy, the SINGLE_TABLE mapping strategy is used.

Syntax: @Inheritance

@Entity
@Table("name = students")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
// Class 
public class Student {

    // Insert code here
}

Annotation 2: @DiscriminatorColumn

This annotation 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 not specified, and the discriminator column is required, in that case, the name of the discriminator column sets to its defaults value “DTYPE” and the discriminator type is set to DiscriminatorType.STRING.

@Entity
@Table("name = students")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "student", discriminatorType = DiscriminatorType.STRING)
// Class 
public class Student {

    // Insert code here
}

Annotations 3: @DiscriminatorValue 

This annotation is used to set the value of the discriminator column for entities of the given type. It can only be specified on a concrete entity class. If @DiscriminatorValue annotation is not mentioned 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 specified as STRING, then the default discriminator value is the name of the entity itself. 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. It is the best practice to specify the discriminator value for each entity class in the hierarchy.

@Entity
@Table("name = employees")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "employee", discriminatorType = DiscriminatorType.STRING)
// Class 
public class Employee{

    // Insert code here
}

@Entity
@DiscriminatorValue(value = "ceo")
// Class
public class Ceo extends Employee {

     // Insert code here
}

Implementation of Table Per Hierarchy (Using Annotations)

In this example, we will be creating three persistence classes with Employee as parent class and P_Employee and C_Employee as the two subclasses.

Hierarchy of Classes

Hierarchy of Classes

Now in this approach, the entire hierarchy is mapped to a single table.  All attributes of all the classes in the hierarchy are stored in a single table.

Creating  Database Table to persist class Hierarchy

CREATE TABLE `Employee` (
 `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
 `name` VARCHAR(50) NOT NULL DEFAULT '0',
 `age` BIGINT(3) NOT NULL DEFAULT '0',
 `salary` BIGINT(11) NULL DEFAULT NULL,
 `hourlyrate` BIGINT(11) NULL DEFAULT NULL,
 `duration` BIGINT(11) NULL DEFAULT NULL,
 `discriminator` VARCHAR(20) NOT NULL,
  PRIMARY KEY (`id`)
)

The Employee table will store objects of all three classes Employee, P_Employee and C_Employee.

Project Structure (IntelliJ IDEA):

Project Structure

Project Structure

Creating the Employee, P_Employee, and C_Employee classes for the above hierarchy:

Below is the implementation of the Employee.java file:

Java




package com.exploit.model;
 
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.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
 
@Entity
@Table(name = "Employee")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type",
                     discriminatorType
                     = DiscriminatorType.STRING)
@DiscriminatorValue(value = "EMP")
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private int id;
    @Column(name = "name") private String name;
    @Column(name = "age") private int age;
 
    public int getAge() { return age; }
 
    public void setAge(int age) { this.age = age; }
 
    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; }
}


Below is the implementation of the P_Employee.java file:

Java




package com.exploit.model;
 
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
 
@Entity
@DiscriminatorValue(value = "PEMP")
public class P_Employee extends Employee {
 
    @Column(name = "salary") private double salary;
 
    public double getSalary() { return salary; }
 
    public void setSalary(double salary)
    {
        this.salary = salary;
    }
}


Below is the implementation of the C_Employee.java file:

Java




package com.exploit.model;
 
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
 
@Entity
@DiscriminatorValue(value = "CEMP")
public class C_Employee extends Employee {
 
    @Column(name = "hourlyRate") private double hourlyRate;
 
    @Column(name = "duration") private double duration;
 
    public double getDuration() { return duration; }
 
    public void setDuration(double duration)
    {
        this.duration = duration;
    }
 
    public double getHourlyRate() { return hourlyRate; }
 
    public void setHourlyRate(double hourlyRate)
    {
        this.hourlyRate = hourlyRate;
    }
}


We have defined discriminators as :  

  • “EMP” will be persisted in the discriminator column belonging to the Employee class.
  • “PEMP” will be persisted in the discriminator column belonging to the P_Employee class.
  • “CEMP” will be persisted in the discriminator column belonging to the C_Employee class.

Creating a hibernate.cgf.xml configuration file and adding the entries of mapping resources:

XML




<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
 
<hibernate-configuration>
 
    <session-factory>
 
        <!-- Database connection properties -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost/heistmvr</property>
        <property name="connection.username">root</property>
        <property name="connection.password">root</property>
 
        <!-- JDBC connection pool (using the built-in) -->
        <property name="connection.pool_size">100</property>
 
        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</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>
 
        <!-- Format the generated Sql -->
        <property name="format_sql">true</property>
 
        <!-- Dont Drop and re-create the database
             schema on startup,Just update it -->
        <property name="hbm2ddl.auto">update</property>
       
        <!-- Entries of mapping resources -->
        <mapping class="com.exploit.model.Employee"/>
        <mapping class="com.exploit.model.C_Employee"/>
        <mapping class="com.exploit.model.P_Employee"/>
 
    </session-factory>
 
</hibernate-configuration>


Following are the dependencies used in the pom.xml file:

XML




         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>TablePerHierarchyAnnotation</groupId>
    <artifactId>TablePerHierarchyAnnotation</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
 
    <name>TablePerHierarchyAnnotation</name>
    <url>http://maven.apache.org</url>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.2.6.Final</version>
        </dependency>
       
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>6.0.5</version>
        </dependency>
       
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-annotations</artifactId>
            <version>3.5.6-Final</version>
        </dependency>
 
    </dependencies>
</project>


Creating the class that stores the persistent object:

Below is the implementation of the Main.java file: 

Java




package com.exploit.db;
 
import com.exploit.model.C_Employee;
import com.exploit.model.Employee;
import com.exploit.model.P_Employee;
import com.exploit.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
 
public class Main {
    public static void main(String[] args)
    {
        // Get session factory using Hibernate Util class
        SessionFactory sessionFactory
            = HibernateUtil.getSessionFactory();
       
        // Get session from Session factory
        Session session = sessionFactory.openSession();
 
        // Begin transaction
        Transaction transaction
            = session.beginTransaction();
 
        // Creating Employee base class record
        Employee employee = new Employee();
        employee.setName("KirikoChan");
        employee.setAge(19);
        // Creating Permanent Employee subclass record
        P_Employee permanentEmployee = new P_Employee();
        permanentEmployee.setName("Saili.H");
        permanentEmployee.setAge(20);
        permanentEmployee.setSalary(30000);
 
        // Creating Contract Employee subclass record
        C_Employee contractEmployee = new C_Employee();
        contractEmployee.setName("ChikkoRita");
        contractEmployee.setAge(21);
        contractEmployee.setHourlyRate(2000);
        contractEmployee.setDuration(7.5);
 
        // persist all the employee records
        session.persist(employee);
        session.persist(permanentEmployee);
        session.persist(contractEmployee);
 
        // Commit the transaction and close the session
        transaction.commit();
        session.close();
        System.out.println(
            "Employee records successfully persisted.");
    }
}


The Main class is used to persist all the three classes’ object instances. Note that both these classes are persisted in the same table Employee. The discriminator column is used to distinguish between the entities. This is the usual way of mapping Table Per Hierarchy using annotations.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads