liveBook · Manning

Single-table inheritance strategy

As explained in Java Persistence with Spring Data and Hibernate epub

A single-table inheritance strategy stores an entire class hierarchy in one table, typically distinguishing subtype rows with a discriminator and allowing nullable subtype columns.

Single-table inheritance stores every class in an entity hierarchy in one table. A discriminator identifies each row’s concrete type, while shared and subtype-specific fields occupy columns in that table. It is a practical fit when code needs polymorphic queries or associations and subclasses add relatively few fields. section 7.3 section 7.7

Listing 7.12 Mapping BillingDetails with SINGLE_TABLE
Path: Ch07/mapping-inheritance-singletable/src/main/java/com/manning
 /javapersistence/ch07/model/BillingDetails.java
 
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "BD_TYPE")
public abstract class BillingDetails {
 
    @Id
    @GeneratedValue(generator = "ID_GENERATOR")
    private Long id;
 
    @NotNull
    @Column(nullable = false)
    private String owner;
 
    //  . . .
}

Map the root entity with @Inheritance(strategy = InheritanceType.SINGLE_TABLE). @DiscriminatorColumn names the type column; @Column(nullable = false) makes the shared owner field non-null in the generated schema. section 7.3

Listing 7.13 Mapping CreditCard using the SINGLE_TABLE inheritance strategy
Path: Ch07/mapping-inheritance-singletable/src/main/java/com/manning
 /javapersistence/ch07/model/CreditCard.java
 
@Entity
@DiscriminatorValue("CC")
public class CreditCard extends BillingDetails {
    @NotNull
    private String cardNumber;
    @NotNull
    private String expMonth;
    @NotNull
    private String expYear;
    //  . . .
}

Map a subclass as an entity and give it an explicit discriminator value. Hibernate uses that value to distinguish its rows from other billing details. section 7.3

Polymorphic and subtype queries

With CreditCard and BankAccount rows in BILLINGDETAILS, a query for BillingDetails reads the hierarchy table and its discriminator. A query for CreditCard adds a BD_TYPE='CC' restriction. Hibernate sets and retrieves discriminator values automatically; the discriminator is not an entity property. section 7.3

The compact schema has a cost: columns used only by one subtype must allow NULL for rows of other types. That prevents a table-level NOT NULL constraint from guaranteeing a required credit-card expiration date. Shared columns can still be NOT NULL. This design also introduces functional dependencies between non-key columns, so weigh apparent performance gains against normalization and data integrity rather than assuming one table is faster. section 7.3

Specify discriminator values explicitly rather than relying on provider-dependent defaults. Without an explicit discriminator column, the default column name is DTYPE. For a schema that lacks a discriminator column, Hibernate also offers @DiscriminatorFormula; one example distinguishes credit cards by whether CARDNUMBER is non-null. section 7.3

A hierarchy uses one inheritance strategy; it cannot simply switch a subclass to JOINED. A targeted workaround is @SecondaryTable: move CreditCard fields to a table keyed to the hierarchy table and map them with @Column(table = "CREDITCARD"). Those fields can then be NOT NULL, but polymorphic loading uses an outer join. Prefer SINGLE_TABLE for simple hierarchies with few nullable subtype columns; consider JOINED when subclasses carry many required fields or normalization and constraints take priority. TABLE_PER_CLASS is another option whose joins-versus-unions tradeoff may require SQL-plan evaluation with real data. section 7.5 section 7.7

A polymorphic one-to-many collection can also target the hierarchy root. That root must be an entity with an inheritance mapping, not a @MappedSuperclass. section 7.8.2

How Java Persistence with Spring Data and Hibernate epub covers it

How deep it goes
Works through annotations, discriminator behavior, generated queries, schema constraints, and a secondary-table workaround; stops short of benchmark results.
Examples
Uses BillingDetails with CreditCard and BankAccount rows, a BD_TYPE discriminator, subtype-filtered SQL, and a CREDITCARD secondary table.
What it assumes
Assumes familiarity with Java entities, relational columns, and queries while spelling out the inheritance annotations and discriminator behavior.
What you can do after
Apply it via JPA annotations, then assess nullable subtype fields and polymorphic needs against JOINED or TABLE_PER_CLASS.
How it connects
Connects discriminator columns, polymorphic queries, nullable columns, normalization, secondary tables, and JOINED and TABLE_PER_CLASS inheritance.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Java Persistence with Spring Data and Hibernate epub. The section links point to the parts of the book it draws on.