Hibernate 5 - Inheritance Mapping

In this tutorial, we will discuss how JPA/Hibernate supports Inheritance mapping. We also look into several inheritance strategies that JPA specification provides.

Relational databases don’t have a straightforward way to map class hierarchies onto database tables.
To address this, the JPA specification provides several strategies:
  1. MappedSuperclass - Inheritance is implemented in the domain model only without reflecting it in the database schema. In this strategy, the parent classes can’t be entities.
  2. Single table - The domain model class hierarchy is materialized into a single table which contains entities belonging to different class types.
  3. Joined table - The base class and all the subclasses have their own database tables and fetching a subclass entity requires a join with the parent table as well.
  4. Table per class - Each subclass has its own table containing both the subclass and the base class properties.
Entity inheritance means that we can use polymorphic queries for retrieving all the sub-class entities when querying for a super-class.
Before get started check out  Hibernate Developer Guide and Spring Hibernate Tutorials to develop J2EE enterprise applications.
Since Hibernate is a JPA implementation, it contains all of the above as well as a few Hibernate-specific features related to inheritance.

Let's discuss each JPA specification inheritance strategies with examples.

1. Hibernate/JPA - MappedSuperclass Inheritance

The JPA standard specification defines the @MappedSuperclass annotation to allow an entity to inherit properties from a base class.
From a database perspective, the @MappedSuperclass inheritance model is invisible since all the base class properties are simply copied to the database table mapped by the actual entity class.

Example: @MappedSuperclass inheritance

In the following domain model class hierarchy, a DebitAccount and a CreditAccount share the same Account base class.
@MappedSuperclass
public static class Account {

    @Id
    private Long id;

    private String owner;

    private BigDecimal balance;

    private BigDecimal interestRate;

    //Getters and setters are omitted for brevity

}

@Entity(name = "DebitAccount")
public static class DebitAccount extends Account {

    private BigDecimal overdraftFee;

    //Getters and setters are omitted for brevity

}

@Entity(name = "CreditAccount")
public static class CreditAccount extends Account {

    private BigDecimal creditLimit;

    //Getters and setters are omitted for brevity

}
CREATE TABLE DebitAccount (
    id BIGINT NOT NULL ,
    balance NUMERIC(19, 2) ,
    interestRate NUMERIC(19, 2) ,
    owner VARCHAR(255) ,
    overdraftFee NUMERIC(19, 2) ,
    PRIMARY KEY ( id )
)

CREATE TABLE CreditAccount (
    id BIGINT NOT NULL ,
    balance NUMERIC(19, 2) ,
    interestRate NUMERIC(19, 2) ,
    owner VARCHAR(255) ,
    creditLimit NUMERIC(19, 2) ,
    PRIMARY KEY ( id )
)
Read more about MappedSuperclass inheritance strategy with example at Hibernate/JPA MappedSuperclass Inheritance Example

2. Hibernate/JPA Single Table Inheritance

The single table strategy maps all entities of the inheritance structure to the same database table. This approach makes polymorphic queries very efficient and provides the best performance.
Note that when no explicit inheritance strategy is registered, Hibernate/JPA will choose the SINGLE_TABLEinheritance strategy by default.
SINGLE_TABLE inheritance performs the best in terms of executed SQL statements. However, you cannot use NOT NULL constraints on the column-level. You can still use triggers and rules to enforce such constraints, but it’s not as straightforward.

Single Table Inheritance Example

Each subclass in a hierarchy must define a unique discriminator value, which is used to differentiate between rows belonging to separate subclass types. If this is not specified, the DTYPE column is used as a discriminator, storing the associated subclass name.
The inheritance strategy is defined on the abstract superclass, using the @Inheritance annotation. In this example, we used InheritanceType.SINGLE_TABLE. This means all concrete subclasses will be stored in one table. You can optionally specify a discriminator column name. This column is registered by the @DiscriminatorColumnif omitted the default DTYPE name is used.
Read complete example at Hibernate/JPA Single Table Inheritance Example

3. Hibernate/JPA Joined Table Inheritance

Each subclass can also be mapped to its own table. This is also called table-per-subclass mapping strategy. An inherited state is retrieved by joining with the table of the superclass.
A discriminator column is not required for this mapping strategy. Each subclass must, however, declare a table column holding the object identifier.
The JOINED table inheritance strategy addresses the data integrity concerns because every subclass is associated with a different table. Polymorphic queries or @OneToMany base class associations don’t perform very well with this strategy. However, polymorphic @ManyToOne associations are fine, and they can provide a lot of value.

Joined Table Inheritance Example

Let's use @Inheritance(strategy = InheritanceType.JOINED) annotation to use this strategy.

package net.javaguides.hibernate.entity;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

@Entity(name = "Account")
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Account {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String owner;

    private double balance;

    private double interestRate;
Demonstrated SINGLE_TABLE inheritance strategy with a complete hibernate example at Hibernate JPA Joined Table Inheritance Example

4. Hibernate/JPA Table Per Class Inheritance

In a Table per class inheritance strategy, each concrete subclass has its own table containing both the subclass and the base class properties.
Example: Use @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
package net.javaguides.hibernate.entity;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

@Entity(name = "Account")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Account {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String owner;

    private double balance;

    private double interestRate;
Demonstrated TABLE_PER_CLASS inheritance strategy with a complete hibernate example at Hibernate/JPA Table Per Class Inheritance Example

GitHub Repository

The complete source code of this article available on my GitHub Repository - https://github.com/RameshMF/Hibernate-ORM-Tutorials

Conclusion

In this article,  we have discussed how JPA/Hibernate supports Inheritance mapping. We also looked into several inheritance strategies that JPA specification provides.
You can learn more about Hibernate ORM Framework at Hibernate Tutorial

References

Hibernate ORM 5.4.0.Final User Guide 

Comments