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.
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.
Suppose we have a class Person with subclasses Employee and Owner. Following the class diagram and relationship of these classes.
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.
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 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`)
)
Code language: SQL (Structured Query Language) (sql)
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,
}
Code language: Java (java)
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,
}
Code language: Java (java)
File: Owner.java
package net.viralpatel.hibernate;
public class Owner extends Person {
private Long stocks;
private Long partnershipStake;
// Constructors and Getter/Setter methods,
}
Code language: Java (java)
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>
Code language: HTML, XML (xml)
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.
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,
}
Code language: Java (java)
@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,
}
Code language: Java (java)
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,
}
Code language: Java (java)
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.
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();
}
}
Code language: Java (java)
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.
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 (?, ?, ?, ?, ?)
Code language: SQL (Structured Query Language) (sql)
Hibernate-inheritance-table-per-concrete-class_xml.zip (9 KB)
Hibernate-inheritance-table-per-concrete-class_annotation.zip (9 KB)
Java URL Encoder/Decoder Example - In this tutorial we will see how to URL encode/decode…
Show Multiple Examples in OpenAPI - OpenAPI (aka Swagger) Specifications has become a defecto standard…
Local WordPress using Docker - Running a local WordPress development environment is crucial for testing…
1. JWT Token Overview JSON Web Token (JWT) is an open standard defines a compact…
GraphQL Subscription provides a great way of building real-time API. In this tutorial we will…
1. Overview Spring Boot Webflux DynamoDB Integration tests - In this tutorial we will see…
View Comments
hi viral,
good article.
Thanks :)
Good Job and great explained Mr. Viral.
Thanks A Lot
:-)
vipul sir,
the HIBERNATE phrases say meaning clearly 1> table per subclass(only subclasses store infomation no super class table)
2>table per Concrete class------(only object existed classes posses database table)
but in ur 2 examples both scenarios has 3 tables(base- derived-derived) its a bit confusing
can u put just theritical explanation on this.
hi sir u have done grate job.
Thanks Viral, for good explanation
Thanks Viral its great really its very very useful
awesome tutorial .!! thanks .!!
Good Article....... for hibernate inheritance
nice explanation thanQ u viral
I don't see repetition of data.. for example... James and Bill are not appearing in the Person table
Its very nice & almost very useful for everyone especially for beginners.
awesome :P