Hibernate 5 - Inheritance Mapping


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. See MappedSuperclass.
  2. Single table - The domain model class hierarchy is materialized into a single table which contains entities belonging to different class types. See Single table.
  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. See Joined table.
  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 Accountbase 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 )
)
For complete MappedSuperclass inheritance strategy 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.

Creating Models + Hibernate/JPA Mappings

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.
Example: Use @Inheritance(strategy = InheritanceType.JOINED)
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

Comments