Hibernate Inheritance: Table Per Concrete Class (Annotation & XML mapping)

Welcome to Hibernate Tutorial Series. In previous tutorials we saw how to implement Inheritance in Hibernate: One Table per Subclass.

Today we will see how to implement Hibernate Inheritance: One Table per Concrete Class scheme.

You may want to look at previous tutorials. Here is the complete list for you.


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 Concrete Class example

Suppose we have a class Person with subclasses Employee and Owner. Following the class diagram and relationship of these classes.

hibernate-table-per-subclass-class-diagram-uml

In One Table per Concrete class scheme, each concrete class is mapped as normal persistent class. Thus we have 3 tables; PERSON, EMPLOYEE and OWNER to persist the class data. In this scheme, the mapping of the subclass repeats the properties of the parent class.

Following are the advantages and disadvantages of One Table per Subclass scheme.

Advantages

  • This is the easiest method of Inheritance mapping to implement.

Disadvantages

  • Data thats belongs to a parent class is scattered across a number of subclass tables, which represents concrete classes.
  • This hierarchy is not recommended for most cases.
  • Changes to a parent class is reflected to large number of tables
  • A query couched in terms of parent class is likely to cause a large number of select operations

This strategy has many drawbacks (esp. with polymorphic queries and associations) explained in the JPA spec, the Hibernate reference documentation, Hibernate in Action, and many other places. Hibernate work around most of them implementing this strategy using SQL UNION queries. It is commonly used for the top level of an inheritance hierarchy:

Create Database Table to persist Concrete classes

CREATE TABLE `person` (
	`person_id` BIGINT(20) NOT NULL AUTO_INCREMENT,
	`firstname` VARCHAR(50) NOT NULL DEFAULT '0',
	`lastname` VARCHAR(50) NOT NULL DEFAULT '0',
	PRIMARY KEY (`person_id`)
)

CREATE TABLE `employee` (
	`person_id` BIGINT(10) NOT NULL AUTO_INCREMENT,
	`firstname` VARCHAR(50) NOT NULL,
	`lastname` VARCHAR(50) NOT NULL,
	`joining_date` DATE NULL DEFAULT NULL,
	`department_name` VARCHAR(50) NULL DEFAULT NULL,
	PRIMARY KEY (`person_id`)
)

CREATE TABLE `owner` (
	`person_id` BIGINT(20) NOT NULL AUTO_INCREMENT,
	`firstname` VARCHAR(50) NOT NULL DEFAULT '0',
	`lastname` VARCHAR(50) NOT NULL DEFAULT '0',
	`stocks` BIGINT(11) NULL DEFAULT NULL,
	`partnership_stake` BIGINT(11) NULL DEFAULT NULL,
	PRIMARY KEY (`person_id`)
)


Project Structure in Eclipse

For XML mapping

hibernate-table-per-concrete-class-xml-project-structure

For Annotation mapping

hibernate-table-per-concrete-class-annotation-project-structure

Hibernate Inheritance: XML Mapping

Following is the example where we map Person, Employee and Owner 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, 
}

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, 
}

File: Owner.java

package net.viralpatel.hibernate;

public class Owner extends Person {

		private Long stocks;
		private Long partnershipStake;

	// Constructors and Getter/Setter methods, 
}

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">
		<id name="personId" column="PERSON_ID">
			<generator class="native" />
		</id>
		<property name="firstname" />
		<property name="lastname" column="lastname" />

	</class>

	<class name="Employee">
		<id name="personId" column="PERSON_ID">
			<generator class="native" />
		</id>
		<property name="firstname" />
		<property name="lastname" column="lastname" />
		<property name="departmentName" column="department_name" />
		<property name="joiningDate" type="date" column="joining_date" />
	</class>

	<class name="Owner">
		<id name="personId" column="PERSON_ID">
			<generator class="native" />
		</id>
		<property name="firstname" />
		<property name="lastname" column="lastname" />
		<property name="stocks" column="stocks" />
		<property name="partnershipStake" column="partnership_stake" />
	</class>
</hibernate-mapping>


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.

We mapped all the classes using simple <class> tag in hbm. This is the usual way of mapping classes in XML.

Hibernate Inheritance: Annotation Mapping

Following is the example where we map Person, Employee and Owner entity classes using JPA Annotations.

File: Person.java

package net.viralpatel.hibernate;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;


@Entity
@Table(name = "PERSON")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Person {

	@Id
	@Column(name = "PERSON_ID")
	private Long personId;
	
	@Column(name = "FIRSTNAME")
	private String firstname;
	
	@Column(name = "LASTNAME")
	private String lastname;
	
	public Person() {
	
	}
	public Person(String firstname, String lastname) {
		this.firstname = firstname;
		this.lastname = lastname;
	}
	// Getter and Setter methods, 
}


@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.

@InheritanceType – Defines inheritance strategy options. TABLE_PER_CLASS is a strategy to map table per concrete class.

File: Employee.java

package net.viralpatel.hibernate;

import java.util.Date;

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

@Entity
@Table(name="EMPLOYEE")
@AttributeOverrides({
    @AttributeOverride(name="firstname", column=@Column(name="FIRSTNAME")),
    @AttributeOverride(name="lastname", column=@Column(name="LASTNAME"))
})
public class Employee extends Person {

	@Column(name="joining_date")
	private Date joiningDate;
	
	@Column(name="department_name")
	private String departmentName;

	public Employee() {
	}
	
	public Employee(String firstname, String lastname, String departmentName, Date joiningDate) {
		
		super(firstname, lastname);
		
		this.departmentName = departmentName;
		this.joiningDate = joiningDate;
	}
	
	// Getter and Setter methods, 
}

File: Owner.java

package net.viralpatel.hibernate;

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

@Entity
@Table(name="OWNER")
@AttributeOverrides({
    @AttributeOverride(name="firstname", column=@Column(name="FIRSTNAME")),
    @AttributeOverride(name="lastname", column=@Column(name="LASTNAME"))
})
public class Owner extends Person {

	@Column(name="stocks")
	private Long stocks;
	
	@Column(name="partnership_stake")
	private Long partnershipStake;

	public Owner() {
	}
	
	public Owner(String firstname, String lastname, Long stocks, Long partnershipStake) {
		
		super(firstname, lastname);
		
		this.stocks = stocks;
		this.partnershipStake = partnershipStake;
	}

	// Getter and Setter methods, 
}


Both Employee and Owner classes are child of Person class. Thus while specifying the mappings, we used @AttributeOverrides to map them.

@AttributeOverrides – This annotation is used to override mappings of multiple properties or fields.

@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.

The AttributeOverride 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 AttributeOverride annotation is not specified, the column is mapped the same as in the original mapping.

Thus in over case, firstname and lastname are defined in parent class Person and mapped in child class Employee and Owner using @AttributeOverrides annotation.

This strategy supports one-to-many associations provided that they are bidirectional. This strategy does not support the IDENTITY generator strategy: the id has to be shared across several tables. Consequently, when using this strategy, you should not use AUTO nor IDENTITY. Note that in below Main class we specified the primary key explicitly.

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");
		person.setPersonId(1L);
		session.save(person);

		Employee employee = new Employee("James", "Gosling", "Marketing", new Date());
		employee.setPersonId(2L);
		session.save(employee);

		Owner owner = new Owner("Bill", "Gates", 300L, 20L);
		owner.setPersonId(3L);
		session.save(owner);

		
		session.getTransaction().commit();
		session.close();

	}
}

The Main class is used to persist Person, Employee and Owner object instances. Note that these classes are persisted in different tables and parent attributes (firstname, lastname) are repeated across all tables.

Output

Hibernate: insert into PERSON (FIRSTNAME, LASTNAME, PERSON_ID) values (?, ?, ?)
Hibernate: insert into EMPLOYEE (FIRSTNAME, LASTNAME, department_name, joining_date, PERSON_ID) values (?, ?, ?, ?, ?)
Hibernate: insert into OWNER (FIRSTNAME, LASTNAME, partnership_stake, stocks, PERSON_ID) values (?, ?, ?, ?, ?)

hibernate-table-per-concrete-class-output


Download Source Code

Hibernate-inheritance-table-per-concrete-class_xml.zip (9 KB)
Hibernate-inheritance-table-per-concrete-class_annotation.zip (9 KB)



35 Comments

  • swaminathan 17 February, 2012, 17:03

    hi viral,
    good article.

  • saurabh jain 23 February, 2012, 19:42

    hi sir u have done grate job.

  • Raymond Antony 9 March, 2012, 11:41

    Thanks Viral, for good explanation

  • Manoj Sharma 30 March, 2012, 12:26

    Thanks Viral its great really its very very useful

  • Ankur 18 April, 2012, 18:45

    awesome tutorial .!! thanks .!!

  • nazeer 8 May, 2012, 14:51

    Good Article……. for hibernate inheritance

  • anilkumarreddy 19 June, 2012, 11:39

    nice explanation thanQ u viral

  • Vijay Nistala 3 July, 2012, 1:15

    I don’t see repetition of data.. for example… James and Bill are not appearing in the Person table

  • Vignesh 6 July, 2012, 19:22

    Its very nice & almost very useful for everyone especially for beginners.

  • Manjeet Rulhania 10 July, 2012, 22:06

    awesome :P

  • sivakrishna 1 August, 2012, 15:11

    Thanks for u r explanation .it helps me alot to resolve my issues.

  • varun 2 August, 2012, 12:24

    U r setting the code as followings:
    person.setPersonId(1L);
    employee.setPersonId(2L);
    owner.setPersonId(3L);

    For which the output is different in which everywhere its showing the id as 1 in all the three tables.

  • Jagpreet 4 October, 2012, 16:43

    I second Varun, i noticed the same issue. Something is wrong.

  • arjun 25 October, 2012, 14:04

    There is problem with primary key. Its not constant in all the three tables as you have shown in the tutorial.

  • George 1 November, 2012, 0:29

    I think the result db image is wrong, there whould be 3 rows in Person don’t you think? because you inserted 1 of each kind of data (three), 1 Person, 1 employee (Person), 1 Owner (Person)… and 1 row in the other tables…
    The correct way would be NOT to override the fields.
    I dont see how data is scattered in other tables, the design is normalized when holding data specific to each table/class. The employee has a name, becuase the employee is a person that has a name.
    It was a great tutorial. Thank you very much!!! :)

    • George 1 November, 2012, 0:35

      My mistake, i confused JOINED withe SINGLE_TABLE…. XD

  • ram 15 November, 2012, 18:54

    nice tut

  • jaidev 23 January, 2013, 5:02

    short and to the point Viral.
    I am trying to import this project into my workspace but it complains about -
    An internal error occurred during: “Importing Maven projects”.
    Unsupported IClasspathEntry kind=4

    The reason to import being – i wanted a working inheritance example using mysql.
    I am tryin to have something like this -

    @Entity
    @Table(name = "users")
    @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
    public class User implements Serializable {
    
    	private static final long serialVersionUID = 2266959322847010611L;
    
        @Id
        @GeneratedValue (strategy=GenerationType.IDENTITY)
        Integer id;
        String username;
        // getters and setters
    }
    

    and child class which for now doesn’t have any attributes of its own but only parent’s

    @Entity
    @Table(name = "employees")
    public class Employee extends Users implements Serializable {
    }
    

    I’m afraid it gives me some kind of id generation error even though i have GenerationType.IDENTITY
    Any advice??

    • jaidev 23 January, 2013, 7:38

      works for Display User/Employees. when i change @GeneratedValue (strategy=GenerationType.IDENTITY) in User class to @GeneratedValue (strategy=GenerationType.TABLE).

      But, now when I add a User it gives me ‘hibernate_sequences’ error.

  • santhosh 10 May, 2013, 12:07
    @Entity
    @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
    public abstract class Employee {
    
    	@Id
    	private int empNo;
    	private String empName;
    	private int deptNo;
    
    	public Employee(){
    	}
    
    	public Employee(int empNo,String empName, int deptNo){
    		this.empNo=empNo;
    		this.empName=empName;
    		this.deptNo=deptNo;
    	}
    	public int getEmpNo() {
    		return empNo;
    	}
    	public void setEmpNo(int empNo) {
    		this.empNo = empNo;
    	}
    	public String getEmpName() {
    		return empName;
    	}
    	public void setEmpName(String empName) {
    		this.empName = empName;
    	}
    	public int getDeptNo() {
    		return deptNo;
    	}
    	public void setDeptNo(int deptNo) {
    		this.deptNo = deptNo;
    	}
    }
    

    ———————————————–

    @Entity
    @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
    public class SalariedEmployee extends Employee{
    
    	private double empSal;
    	public SalariedEmployee() {
    	}
    
    	public SalariedEmployee(int empNo,String empName,int deptNo,double empSal){
    		super(empNo,empName,deptNo);
    		this.empSal=empSal;
    	}
    	public double getEmpSal() {
    		return empSal;
    	}
    	public void setEmpSal(double empSal) {
    		this.empSal = empSal;
    	}
    }
    

    ————————————————–

    @Entity
    @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
    public class HourlyEmployee extends Employee{
    	
    	private int maxHoursPerDay;
    	private int ratePerHour;
    	
    	public HourlyEmployee(){
    		
    	}
    	
    	public HourlyEmployee(int empNo,  String empName, int deptNo,int maxHoursPerDay,int ratePerHour){
    		super(empNo,empName,deptNo);
    		this.maxHoursPerDay=maxHoursPerDay;
    		this.ratePerHour=ratePerHour;
    	}
    	public int getMaxHoursPerDay() {
    		return maxHoursPerDay;
    	}
    	public void setMaxHoursPerDay(int maxHoursPerDay) {
    		this.maxHoursPerDay = maxHoursPerDay;
    	}
    	public int getRatePerHour() {
    		return ratePerHour;
    	}
    	public void setRatePerHour(int ratePerHour) {
    		this.ratePerHour = ratePerHour;
    	}
    }
    

    Facing the error:

    Exception in thread “Main Thread” org.hibernate.AnnotationException: No identifier specified for entity: com.st.vo.SalariedEmployee
    at org.hibernate.cfg.InheritanceState.determineDefaultAccessType(InheritanceState.java:268)
    at org.hibernate.cfg.InheritanceState.getElementsToProcess(InheritanceState.java:223)
    at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:686)
    at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3977)
    at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3931)
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1368)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1826)
    at com.st.utils.HibernateUtils.getSessionFactory(HibernateUtils.java:14)
    at com.st.vo.TablePerClassTestCase.main(TablePerClassTestCase.java:14)

    Facing the above error even after providing @identifier …….

    • Viral Patel 10 May, 2013, 14:31

      @Santosh: Can you add generate=GeneratorType.TABLE to @Id definition in Employee class?
      @Id(generate=GeneratorType.TABLE)

  • Swaraj 14 June, 2013, 15:24

    Hi Viral,

    Nice article, But i found many copy paste issue in the these article. Though they are easy to avoid but for beginers, it is little confusing.

    Thanks for sharing.

  • MOHAMMAD 7 July, 2013, 15:53

    nice examle:

    i have same senario example

    in my domain classess i have, person class as abstract class, so no table will be created for person class, i have a case that a person that can be owner and employee at same time, and class owner has set of employees work for that owner.
    owner.class

    import javax.persistence.AttributeOverride;
    import javax.persistence.AttributeOverrides;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.Table;
     
    @Entity
    @Table(name="OWNER")
    @AttributeOverrides({
        @AttributeOverride(name="firstname", column=@Column(name="FIRSTNAME")),
        @AttributeOverride(name="lastname", column=@Column(name="LASTNAME"))
    })
    public class Owner extends Person {
     
        @Column(name="stocks")
        private Long stocks;
         
        @Column(name="partnership_stake")
        private Long partnershipStake;
     
        public Owner() {
        }
         
        public Owner(String firstname, String lastname, Long stocks, Long partnershipStake) {
             
            super(firstname, lastname);
             
            this.stocks = stocks;
            this.partnershipStake = partnershipStake;
        }
     
        // Getter and Setter methods, 
    }
    
  • John 21 August, 2013, 10:38

    Hey,
    Thanks for a good article.

    I just have one concern that when using TABLE_PER_CLASS strategy, do we need to have the physical “Person” table in the database?

  • Ravi 30 September, 2013, 15:20

    Good and well explained tutorial for Hibernate
    Many tutorial are available but this tutorial for Hibernate mapping and Hibernate inheritence concept point of view, I would say it is nice and no comparision at all.

  • Ravi 30 September, 2013, 15:25

    @Viral Patel,
    Please provide us “CURD based Hibernate-Spring” tutorial via using HibernateDAO and HibernateTemplate and HibernateFactory using SessionFactory to do all CURD related functionality to and from MySQL/Oracle database.

  • Ravi 30 September, 2013, 15:30

    @Viral Patel,
    Sir Why you are not providing Spring tutorial like this as Hibernate have (very selected but nicely explained and good one) as there are so many tutorial but Viral Patel sir something we are missing which you can fulfill by providing “Spring Tutorial” for many people in india and abroad.
    Only MkYong is there but you can provide something more than that when you will come into Spring also so please provide some selected great topic relates to Spring Core and Spring MVC also.

  • deveshanand2@gmail.com 24 October, 2013, 19:23
     
    y m getting this exception if i gave sequence in Person.java
    ===============================================
    Initial SessionFactory creation failed.org.hibernate.MappingException: could not instantiate id generator
    Exception in thread "main" java.lang.ExceptionInInitializerError
    	at com.devesh.SpringHibernate.HibernateUtil.buildSessionFactory(HibernateUtil.java:18)
    	at com.devesh.SpringHibernate.HibernateUtil.<clinit>(HibernateUtil.java:8)
    	at com.devesh.SpringHibernate.Main.main(Main.java:12)
    Caused by: org.hibernate.MappingException: could not instantiate id generator
    	at org.hibernate.id.IdentifierGeneratorFactory.create(IdentifierGeneratorFactory.java:98)
    	at org.hibernate.mapping.SimpleValue.createIdentifierGenerator(SimpleValue.java:152)
    	at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:192)
    	at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1294)
    	at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:915)
    	at com.devesh.SpringHibernate.HibernateUtil.buildSessionFactory(HibernateUtil.java:15)
    	... 2 more
    Caused by: org.hibernate.MappingException: Dialect does not support sequences
    	at org.hibernate.dialect.Dialect.getSequenceNextValString(Dialect.java:596)
    	at org.hibernate.id.SequenceGenerator.configure(SequenceGenerator.java:65)
    	at org.hibernate.id.SequenceHiLoGenerator.configure(SequenceHiLoGenerator.java:43)
    	at org.hibernate.id.IdentifierGeneratorFactory.create(IdentifierGeneratorFactory.java:94)
    	... 7 more
    
    Person.java
    ==========
    public Person(String firstname, String lastname) {
            this.firstname = firstname;
            this.lastname = lastname;
        }
        @Id  
        @SequenceGenerator(name="sequence", sequenceName="mySequence")
    	@GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="sequence")
    	
       @Column(name="person_id", unique=true, nullable=false)
    
    //having getter and setting method of id, firstname, lastname
    
    Employee,java and Owner.java   ---> same as of ur application
    and rest all the same of ur application
    
  • Nadeem 5 November, 2013, 15:19

    Hi Viral

    I am getting an error for the “Hibernate Inheritance: Table Per Concrete Class (Annotation & XML mapping)” example… The error is as below…

    Note: I am using Hibernate 3.6 and mysql 5.5

    Exception in thread “main” org.hibernate.exception.GenericJDBCException: could not insert: [com.viralpatel.tableperconcreteclass.Employee]

    Caused by: java.sql.SQLException: Field ‘DISCRIMINATOR’ doesn’t have a default value

    Please assist, if possible..

    Regards
    Nadeem

  • Pravin Panicker 26 November, 2013, 11:31

    Fantastic article, Viral. Very well written, clear and concise. One of the best links explaining one to many and hierarchy in hibernate. Thanks a lot.

  • Madhu 2 December, 2013, 20:24

    it is explained in a nice way. Keep it up, Viral.

  • Sanjay 29 January, 2014, 15:21

    Hi Viral,

    Thanks for giving Good Example.

    I have one problem with the update.
    EX: If i try to update Owner using update query it fails because of inheritance issue.

    Can you please provide some suggetions?

Leave a Reply

Your email address will not be published. Required fields are marked *

Note

To post source code in comment, use [code language] [/code] tag, for example:

  • [code java] Java source code here [/code]
  • [code html] HTML here [/code]