Table per concrete class with Annotation

In previous article we saw Table per Concrete class using XML

In this article, we will learn the same using Annotation.

Let us understand about Table Per Concrete class with Annotation

Let’s create hibernate project using Annotation

Step 1

Create hibernate project

Please refer Hibernate setup in eclipse article on how to do it.

Project Structure


TPCC_Annotation_Proj_structure

Step 2

Update pom.xml with Hibernate and Mysql dependencies

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2.   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3.   <modelVersion>4.0.0</modelVersion>
  4.  
  5.   <groupId>TablePerConcreteClassAnnotation</groupId>
  6.   <artifactId>TablePerConcreteClassAnnotation</artifactId>
  7.   <version>0.0.1-SNAPSHOT</version>
  8.   <packaging>jar</packaging>
  9.  
  10.   <name>TablePerConcreteClassAnnotation</name>
  11.   <url>http://maven.apache.org</url>
  12.  
  13.   <properties>
  14.     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  15.   </properties>
  16.  
  17.   <dependencies>
  18.     <dependency>
  19.       <groupId>junit</groupId>
  20.       <artifactId>junit</artifactId>
  21.       <version>3.8.1</version>
  22.       <scope>test</scope>
  23.     </dependency>
  24.    
  25.     <dependency>
  26.     <groupId>org.hibernate</groupId>
  27.     <artifactId>hibernate-core</artifactId>
  28.     <version>5.2.6.Final</version>
  29.     </dependency>
  30.  
  31. <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
  32.     <dependency>
  33.         <groupId>mysql</groupId>
  34.         <artifactId>mysql-connector-java</artifactId>
  35.      <version>6.0.5</version>
  36.      </dependency>
  37.  
  38. <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-annotations -->
  39.      <dependency>
  40.     <groupId>org.hibernate</groupId>
  41.     <artifactId>hibernate-annotations</artifactId>
  42.     <version>3.5.6-Final</version>
  43.      </dependency>
  44.        
  45.   </dependencies>
  46. </project>
<project xmlns="http://maven.apache.org/POM/4.0.0" 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>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>

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
	 <version>6.0.5</version>
     </dependency>

<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-annotations -->
     <dependency>
	<groupId>org.hibernate</groupId>
	<artifactId>hibernate-annotations</artifactId>
	<version>3.5.6-Final</version>
     </dependency>
		
  </dependencies>
</project>

Step 3

Create Employee class

  1. package com.kb.model;
  2.  
  3. import javax.persistence.Column;
  4. import javax.persistence.Entity;
  5. import javax.persistence.GeneratedValue;
  6. import javax.persistence.GenerationType;
  7. import javax.persistence.Id;
  8. import javax.persistence.Inheritance;
  9. import javax.persistence.InheritanceType;
  10. import javax.persistence.Table;
  11.  
  12. @Entity
  13. @Table(name = "Employee2")
  14. @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
  15.  
  16. public class Employee {
  17.  
  18.     @Id
  19.     @GeneratedValue(strategy = GenerationType.AUTO)
  20.     @Column(name = "id")
  21.     private int id;
  22.    
  23.     @Column(name = "name")
  24.     private String name;
  25.    
  26.     @Column(name="city")
  27.     private String city;
  28.  
  29.     public int getId() {
  30.         return id;
  31.     }
  32.  
  33.     public void setId(int id) {
  34.         this.id = id;
  35.     }
  36.  
  37.     public String getName() {
  38.         return name;
  39.     }
  40.  
  41.     public void setName(String name) {
  42.         this.name = name;
  43.     }
  44.    
  45.     public String getCity() {
  46.         return city;
  47.     }
  48.  
  49.     public void setCity(String city) {
  50.         this.city = city;
  51.     }
  52. }
package com.kb.model;

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;

@Entity
@Table(name = "Employee2")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

public class Employee {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "id")
	private int id;
	
	@Column(name = "name")
	private String name;
	
	@Column(name="city")
	private String city;

	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 String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}
}


@Entity annotation is used to indicate the class as persistent entity.

@Table annotation indicates the table name where this entity has to be persisted

@Inheritance annotation is used for implementing inheritance in hibernate.

It helps us to define the inheritance strategy.

We have used TABLE_PER_CLASS as inheritance strategy.

@Inheritance annotation is defined at root class level or sub hierarchy class level where different strategy has to be applied.

@Id is used to specify the primary key column.

@GeneratedValue is used to specify the primary key generation strategy.

@Column is used to specify the details of the column to which a field or property will be mapped

Step 4

Create PermanentEmployee class

  1. package com.kb.model;
  2.  
  3. import javax.persistence.Column;
  4. import javax.persistence.Entity;
  5. import javax.persistence.Table;
  6.  
  7. @Entity
  8. @Table(name = "PermanentEmployee")
  9. public class PermanentEmployee extends Employee {
  10.  
  11.     @Column(name = "salary")
  12.     private double salary;
  13.  
  14.     public double getSalary() {
  15.         return salary;
  16.     }
  17.  
  18.     public void setSalary(double salary) {
  19.         this.salary = salary;
  20.     }
  21.  
  22. }
package com.kb.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name = "PermanentEmployee")
public class PermanentEmployee extends Employee {

	@Column(name = "salary")
	private double salary;

	public double getSalary() {
		return salary;
	}

	public void setSalary(double salary) {
		this.salary = salary;
	}

}

Step 5

Create ContractEmployee class

  1. package com.kb.model;
  2.  
  3. import javax.persistence.Column;
  4. import javax.persistence.Entity;
  5. import javax.persistence.Table;
  6.  
  7. @Entity
  8. @Table(name = "ContractEmployee")
  9. public class ContractEmployee extends Employee {
  10.    
  11.     @Column(name = "hourlyRate")
  12.     private double hourlyRate;
  13.  
  14.     public double getHourlyRate() {
  15.         return hourlyRate;
  16.     }
  17.  
  18.     public void setHourlyRate(double hourlyRate) {
  19.         this.hourlyRate = hourlyRate;
  20.     }
  21.  
  22. }
package com.kb.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name = "ContractEmployee")
public class ContractEmployee extends Employee {
	
	@Column(name = "hourlyRate")
	private double hourlyRate;

	public double getHourlyRate() {
		return hourlyRate;
	}

	public void setHourlyRate(double hourlyRate) {
		this.hourlyRate = hourlyRate;
	}

}

Step 6

Create hibernate.cfg.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE hibernate-configuration PUBLIC
  3.        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
  4.        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
  5.  
  6. <hibernate-configuration>
  7.  
  8.     <session-factory>
  9.  
  10.         <!-- Database connection properties -->
  11.         <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
  12.         <property name="connection.url">jdbc:mysql://localhost/javainsimpleway</property>
  13.         <property name="connection.username">root</property>
  14.         <property name="connection.password">root</property>
  15.  
  16.         <!-- JDBC connection pool (using the built-in) -->
  17.         <property name="connection.pool_size">100</property>
  18.  
  19.         <!-- SQL dialect -->
  20.         <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
  21.  
  22.         <!-- Disable the second-level cache -->
  23.         <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
  24.  
  25.         <!-- Echo all executed SQL to stdout -->
  26.         <property name="show_sql">true</property>
  27.  
  28.         <!-- Format the generated Sql -->
  29.         <property name="format_sql">true</property>
  30.  
  31.         <!-- Dont Drop and re-create the database schema on startup,Just update
  32.             it -->
  33.         <property name="hbm2ddl.auto">update</property>
  34.  
  35.         <mapping class="com.kb.model.Employee" />
  36.         <mapping class="com.kb.model.ContractEmployee" />
  37.         <mapping class="com.kb.model.PermanentEmployee" />
  38.  
  39.     </session-factory>
  40.  
  41. </hibernate-configuration>
<?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 properties -->
		<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="connection.url">jdbc:mysql://localhost/javainsimpleway</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>

		<mapping class="com.kb.model.Employee" />
		<mapping class="com.kb.model.ContractEmployee" />
		<mapping class="com.kb.model.PermanentEmployee" />

	</session-factory>

</hibernate-configuration>


We have defined the entire database configuration in this file

hbm2ddl.auto property is defined in the config file which helps in automatic creation of tables in the database based on the mapping.

We have provided hbm2ddl.auto as Update so that it won’t delete any existing schema or tables, rather it will just update with new tables.

We have also provided the mapping class names where we have added the annotations using “mapping” tag.

Step 7

Create Hibernate util class

  1. package com.kb.util;
  2.  
  3. import org.hibernate.SessionFactory;
  4. import org.hibernate.cfg.Configuration;
  5.  
  6. public class HibernateUtil {
  7.     private static final SessionFactory sessionFactory = buildSessionFactory();
  8.  
  9.     private static SessionFactory buildSessionFactory() {
  10.         try {
  11.             // Create the SessionFactory from hibernate.cfg.xml
  12.             return new Configuration().configure().buildSessionFactory();
  13.         } catch (Throwable ex) {
  14.             // Make sure you log the exception to track it
  15.             System.err.println("SessionFactory creation failed." + ex);
  16.             throw new ExceptionInInitializerError(ex);
  17.         }
  18.     }
  19.  
  20.     public static SessionFactory getSessionFactory() {
  21.         return sessionFactory;
  22.     }
  23.    
  24.     public static void shutdown() {
  25.         // Optional but can be used to Close caches and connection pools
  26.         getSessionFactory().close();
  27.     }
  28.  
  29. }
package com.kb.util;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {
	private static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            // Make sure you log the exception to track it
            System.err.println("SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
    
    public static void shutdown() {
    	// Optional but can be used to Close caches and connection pools
    	getSessionFactory().close();
    }

}

Step 8

Create main class to interact with DB

  1. package com.kb.db;
  2.  
  3. import org.hibernate.Session;
  4. import org.hibernate.SessionFactory;
  5. import org.hibernate.Transaction;
  6.  
  7. import com.kb.model.ContractEmployee;
  8. import com.kb.model.Employee;
  9. import com.kb.model.PermanentEmployee;
  10. import com.kb.util.HibernateUtil;
  11.  
  12. public class Main {
  13.     public static void main(String[] args) {
  14.         //Get session factory using Hibernate Util class
  15.         SessionFactory sf = HibernateUtil.getSessionFactory();
  16.         //Get session from Sesson factory
  17.         Session session = sf.openSession();
  18.        
  19.         //Begin transaction
  20.         Transaction t=session.beginTransaction();  
  21.  
  22.         //Creating Employee base class record
  23.         Employee employee=new Employee();  
  24.         employee.setName("John");
  25.         employee.setCity("Newyork");
  26.        
  27.         //Creating Permanent Employee subclass record
  28.         PermanentEmployee permanentEmployee=new PermanentEmployee();  
  29.         permanentEmployee.setName("Jacob");  
  30.         permanentEmployee.setCity("Delhi");
  31.         permanentEmployee.setSalary(30000);  
  32.        
  33.        //Creating Contract Employee subclass record
  34.         ContractEmployee contractEmployee=new ContractEmployee();  
  35.         contractEmployee.setName("Raj");
  36.         contractEmployee.setCity("Arizona");
  37.         contractEmployee.setHourlyRate(2000);  
  38.        
  39.         //persist all the employee records
  40.         session.persist(employee);  
  41.         session.persist(permanentEmployee);  
  42.         session.persist(contractEmployee);  
  43.        
  44.         //Commit the transaction and close the session
  45.         t.commit();  
  46.         session.close();  
  47.         System.out.println("successfully persisted all the Employee records");  
  48.     }
  49.  
  50. }
package com.kb.db;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import com.kb.model.ContractEmployee;
import com.kb.model.Employee;
import com.kb.model.PermanentEmployee;
import com.kb.util.HibernateUtil;

public class Main {
	public static void main(String[] args) {
		//Get session factory using Hibernate Util class
		SessionFactory sf = HibernateUtil.getSessionFactory();
		//Get session from Sesson factory
		Session session = sf.openSession();
		
		//Begin transaction
		Transaction t=session.beginTransaction();  

		//Creating Employee base class record
		Employee employee=new Employee();  
		employee.setName("John");
		employee.setCity("Newyork");
	    
		//Creating Permanent Employee subclass record
	    PermanentEmployee permanentEmployee=new PermanentEmployee();  
	    permanentEmployee.setName("Jacob");  
	    permanentEmployee.setCity("Delhi");
	    permanentEmployee.setSalary(30000);  
	    
	   //Creating Contract Employee subclass record
	    ContractEmployee contractEmployee=new ContractEmployee();  
	    contractEmployee.setName("Raj");
	    contractEmployee.setCity("Arizona");
	    contractEmployee.setHourlyRate(2000);  
	    
	    //persist all the employee records
	    session.persist(employee);  
	    session.persist(permanentEmployee);  
	    session.persist(contractEmployee);  
	    
	    //Commit the transaction and close the session
	    t.commit();  
	    session.close();  
	    System.out.println("successfully persisted all the Employee records");  
	}

}

Step 9

Run the above class to check the output

Hibernate: 

create table ContractEmployee (

       id integer not null,

        city varchar(255),

        name varchar(255),

        hourlyRate double precision,

        primary key (id)
    )


Hibernate: 
    
    create table Employee2 (

       id integer not null,

        city varchar(255),

        name varchar(255),

        primary key (id)
    )


Hibernate: 
    
    create table hibernate_sequence (

       next_val bigint
    )


Hibernate: 
    
    insert into hibernate_sequence values ( 1 )


Hibernate: 
    
    create table PermanentEmployee (

       id integer not null,

        city varchar(255),

        name varchar(255),

        salary double precision,

        primary key (id)
    )


Hibernate: 

    select
        next_val as id_val 

    from
        hibernate_sequence for update

            
Hibernate: 

    update
        hibernate_sequence 

    set
        next_val= ? 

    where
        next_val=?


Hibernate: 

    select
        next_val as id_val 

    from
        hibernate_sequence for update

            
Hibernate: 

    update
        hibernate_sequence 

    set
        next_val= ? 

    where
        next_val=?


Hibernate: 

    select
        next_val as id_val 

    from
        hibernate_sequence for update

            
Hibernate: 

    update
        hibernate_sequence 

    set
        next_val= ? 

    where
        next_val=?


Hibernate: 

    insert 

    into
        Employee2

        (city, name, id) 

    values

        (?, ?, ?)


Hibernate: 

    insert 

    into

        PermanentEmployee

        (city, name, salary, id) 

    values

        (?, ?, ?, ?)


Hibernate: 

    insert 

    into

        ContractEmployee

        (city, name, hourlyRate, id) 

    values

        (?, ?, ?, ?)

successfully persisted all the Employee records


We can see 3 Create statements to create 3 tables are executed.

We can see 3 statements for updating the auto generated primary key for ID are executed.

3 insert statements one for each object we persisted are executed.

Check Table in MYSQL console

E:\MySql_Install\bin
Mysql –u root –p
Enter password

SELECT * FROM Employee2;

SELECT * FROM PermanentEmployee;

SELECT * FROM ContractEmployee;

TPCC_Output1

We can see that id,Name and City columns of parent class table are duplicated in each subclass tables.

Advantage

Easy to implement and avoid the NULL values getting stored in the columns

Disadvantage

Columns in parent class table are duplicated in each subclass table.

Any change in the parent class table will impact all the subclass tables.

Note :This strategy is not completely normalized as it still have duplicate columns in each subclass table.

About the Author

Founder of javainsimpleway.com
I love Java and open source technologies and very much passionate about software development.
I like to share my knowledge with others especially on technology 🙂
I have given all the examples as simple as possible to understand for the beginners.
All the code posted on my blog is developed,compiled and tested in my development environment.
If you find any mistakes or bugs, Please drop an email to kb.knowledge.sharing@gmail.com

Connect with me on Facebook for more updates

Share this article on