Spring Boot: JPA Inherence

Spring Boot JPA Inherence

Spring-Boot
JPA
Spring Boot JPA
Author

albertprofe

Published

Tuesday, June 1, 2021

Modified

Saturday, November 2, 2024

📘 JPA Inherence

Spring Boot provides an implementation of the Java Persistence API (JPA) to simplify database access: ORM (Object-Relational Mapping)

In JPA, entity classes represent tables in the database, and relationships between entities are mapped using annotations.

Inheritance is a fundamental concept of POO, but Relational databases have no concept of inheritance neither NoSQL (MongoDB, DymamoDB), so persisting inheritance in a SQL and NoSQL database _has its own particular way.


1 Inherence and JPA

Entity Inheritance

Entity Inheritance

Inheritance is a fundamental concept of POO, but Relational databases have no concept of inheritance neither NoSQL (MongoDB, DymamoDB), so persisting inheritance in a SQL and NoSQL database has its own particular way.

Because relational databases have no concept of inheritance, there is no standard way of implementing inheritance in database, so the hardest part of persisting inheritance is choosing how to represent the inheritance in the database.

JPA defines several inheritance mechanisms, mainly defined though the @Inheritance annotation or the <inheritance> element.

There are three inheritance strategies defined from the InheritanceType enum:

  1. SINGLE_TABLE: SINGLE_TABLE
  2. TABLE_PER_CLASS: TABLE_PER_CLASS
  3. JOINED: JOINED
  • Single table inheritance is the default with discriminator values,
  • and table per class is an optional feature of the JPA spec, so not all providers may support it.
  • in joined strategy each class in the hierarchy is mapped to its table.

MAPPED SUPERCLASS

JPA also defines a mapped superclass concept defined through the @MappedSuperclass annotation or the <mapped-superclass> element.

A mapped superclass is not a persistent class, but allows common mappings to be defined for its subclasses.

  1. MAPPED SUPERCLASS: @MappedSuperClass

Links:

Each strategy has its own advantages and trade-offs in terms of performance, flexibility, and database structure. The choice depends on the specific requirements of our application.

1.1 SINGLE_TABLE

The SINGLE_TABLE strategy maps all classes in the inheritance hierarchy to a single database table. This is the default strategy.

Oracle Official docs

Simple example:

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Animal { 
  // ...
}

@Entity
@DiscriminatorValue("DOG")
public class Dog extends Animal {
  // ...  
}

1.2 TABLE_PER_CLASS

The TABLE_PER_CLASS strategy creates a separate table for each concrete class in the hierarchy.

Oracle Official docs

Simple example:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Vehicle {
  // ...
}

@Entity
public class Car extends Vehicle {
  // ...
}

1.3 JOINED

The JOINED strategy creates a table for the base class and separate tables for each subclass, linked by foreign keys.

Oracle Official docs

Simple example:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Employee {
  // ...
}

@Entity
public class Manager extends Employee {
  // ...
}

2 JPA Inheritance Strategies

In Java Persistence API (JPA), mapping inheritance hierarchies to relational databases presents unique challenges. JPA offers three main strategies to handle this object-relational impedance mismatch:

  1. SINGLE_TABLE: All classes are mapped to one table in the hierarchy .
  2. TABLE_PER_CLASS: Each concrete class gets its own table.
  3. JOINED: The base class and each subclass have their own tables.

The following table summarizes the key aspects of each strategy:

JPA Inheritance Strategies table
Strategy Pros Cons Use Case
SINGLE_TABLE - Simple and fast queries
- Easy to add new types
- Good performance
- Potential for many nullable columns
- Table can become large
- Limited to 31 subclasses (due to dtype limitation)
Best for hierarchies with few subclasses and little variation in properties
TABLE_PER_CLASS - Data integrity (no null columns)
- Easy to add new types
- Each table is self-contained
- Complex queries across hierarchy
- Potential for duplicate columns
- Can be slower for polymorphic queries
Suitable when subclasses have many unique attributes and polymorphic queries are rare
JOINED - Normalized database design
- Flexible for future changes
- Supports polymorphic queries efficiently
- Requires joins for queries
- Inserts and updates affect multiple tables
- Can be slower for deep hierarchies
Ideal for complex hierarchies where data integrity and normalization are important

The choice of strategy should be based on your specific requirements, including performance needs, data structure complexity, and anticipated future changes.

3 Labs

Back to top