Open In App

Hibernate – Table Per Concrete Class Using Annotation

Last Updated : 21 Nov, 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 Concrete class (using Annotations)

Table per Concrete Class is one of the inheritance strategies in hibernate. If we want to keep each concrete class object of inheritance in separate tables of the database then we can proceed with the table per concrete class strategy.

In a Table per Concrete Class strategy:

  • Hibernate stores each derived class object of hierarchy in a separate table of the database.
  • Data that belongs to a parent class is scattered across a number of subclass tables, which represent concrete classes.
  • The discriminator is not required, so we can avoid discriminator-related annotations.

In this strategy, each subclass table will have the subclass-specific attributes and the attributes inherited from the parent class.

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: @AttributeOverride

The @AttributeOverride annotation is used to override the mapping of a Basic (whether explicit or default) property or field or Id property or field. This annotation may be applied to an entity that extends a mapped superclass or to an embedded field or property to override a basic mapping defined by the mapped superclass or embeddable class. If the annotation is not specified, the column is mapped the same as in the original mapping.

Syntax: @AttributeOverride

@Entity
@Table(name="students")
@AttributeOverrides({

    @AttributeOverride(name="name", column=@Column(name="NAME")),

    @AttributeOverride(name="age", column=@Column(name="AGE"))

})
// Class 
public class Student {

    // Insert code here
}

Implementation of Table Per Concrete class (Using Annotations)

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

Hierarchy of Classes

We have 3 tables Employee, P_Employee, and C_Employee. The mapping of the subclass repeats the properties of the parent class.

Creating  Database Table to persist Concrete classes:

CREATE TABLE `Employee` (
        `Id` BIGINT(20) NOT NULL AUTO_INCREMENT,
       `name` VARCHAR(50) NOT NULL DEFAULT '0',
       `age` BIGINT(3) NOT NULL DEFAULT '0',
        PRIMARY KEY (`id`)
)

CREATE TABLE `P_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,
     PRIMARY KEY (`id`)
)

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

The project structure (IntelliJ IDEA)  is as follows: 

Project Structure

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

File: Employee.java

Java




// Java Program to Demonstrate Implementation
// of Employee Class
 
package com.exploit.model;
 
// Importing required classes
import javax.persistence.Column;
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;
 
// Class
@Entity
@Table(name = "Employee2")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Employee {
 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
 
    // Class data member
    private int id;
    @Column(name = "name") private String name;
    @Column(name = "age") private String age;
 
    // Getter and Setters
    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; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
}


File: P_Employee.java

Java




// Java Program to Demonstrate P_Employee Class
 
package com.exploit.model;
 
// Importing required classes
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
 
// Class
@Entity
@Table(name = "P_Employee")
public class P_Employee extends Employee {
 
    // Class data member
    @Column(name = "salary") private double salary;
 
    // Getter and setters
    public double getSalary() { return salary; }
    public void setSalary(double salary)
    {
        // this keyword refers to current instance itself
        this.salary = salary;
    }
}


File: C_Employee.java

Java




// Java Program to Demonstrate Implementation
// of C_Employee Class
 
package com.exploit.model;
 
// Importing required classes
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
 
// Class
@Entity
@Table(name = "C_Employee")
public class C_Employee extends Employee {
 
    // Class data members
    @Column(name = "hourlyRate") private double hourlyRate;
    @Column(name = "duration") private double duration;
 
    // getters and setters
    public double getHourlyRate() { return hourlyRate; }
    public void setHourlyRate(double hourlyRate)
    {
        // this keyword refers to current instance
        this.hourlyRate = hourlyRate;
    }
 
    public double getDuration() { return duration; }
 
    public void setDuration(double duration)
    {
        this.duration = duration;
    }
}


Creating a hibernate.cfg.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/exploitdb</property>
        <property name="connection.username">root</property>
        <property name="connection.password">toor</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>
 
        <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




    <modelVersion>4.0.0</modelVersion>
 
    <groupId>TablePerConcreteClassAnnotation</groupId>
    <artifactId>TablePerConcreteClassAnnotation</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
 
    <name>TablePerConcreteClassAnnotation</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

File: Main.java

Java




// Java Program to Illustrate Application Class
 
package com.exploit.db;
 
// Importing required classes
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;
 
// Main class
public class Main {
 
    // Main driver method
    public static void main(String[] args)
    {
        // Getting session factory using Hibernate Util
        // class
        SessionFactory sessionFactory
            = HibernateUtil.getSessionFactory();
 
        // Getting 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);
 
        // Persisting all the employee records
        session.persist(employee);
        session.persist(permanentEmployee);
        session.persist(contractEmployee);
 
        // Commit the transaction and
        // closing the session
        transaction.commit();
        session.close();
 
        // Display message
        System.out.println(
            "Employee records successfully persisted.");
    }
}


Output:

Employee records successfully persisted.

The Main class is used to persist Employee, P_Employee, and C_Employee object instances. This is the usual way of mapping Table Per Concrete Class using Annotations.



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

Similar Reads