How do you implement inheritance in JPA?

Table of Contents

Introduction

In Java Persistence API (JPA), inheritance is an essential feature that allows you to model object-oriented class hierarchies in relational databases. JPA provides several strategies for mapping the inheritance relationships of Java classes to database tables, making it easier to work with polymorphic objects and manage complex data models.

The @Inheritance annotation in JPA is used to specify the inheritance strategy, determining how subclass entities are stored and retrieved from the database. Depending on the chosen strategy, JPA can map the inheritance hierarchy to one or multiple tables.

In this guide, we'll cover the different inheritance strategies in JPA and demonstrate how to implement inheritance in JPA entities.

Inheritance Strategies in JPA

JPA supports three main inheritance strategies:

  1. Single Table Inheritance (SINGLE_TABLE)
  2. Joined Table Inheritance (JOINED)
  3. Table Per Class Inheritance (TABLE_PER_CLASS)

Each strategy has its own advantages and trade-offs, depending on your application's needs.

1. Single Table Inheritance (SINGLE_TABLE)

In Single Table Inheritance, all classes in the inheritance hierarchy are mapped to a single database table. A special discriminator column is used to differentiate between the different types of entities stored in the same table.

How it works:

  • One table holds the fields of all entities in the hierarchy.
  • A discriminator column is added to identify the specific subclass type of each row.
  • This strategy is simple and efficient but can lead to sparse tables if the subclasses have significantly different fields.

Example:

In the example above:

  • **Vehicle** is the abstract superclass, and both **Car** and **Bike** are concrete subclasses.
  • The **@Inheritance** annotation specifies that SINGLE_TABLE strategy will be used.
  • The **@DiscriminatorColumn** annotation defines a column (type) to distinguish between Car and Bike.
  • **@DiscriminatorValue** is used in each subclass to specify the value of the discriminator column for that type.

The resulting table might look like this:

idmodeltypedoorshasPedals
1SedanCAR4NULL
2MTBBIKENULLtrue

2. Joined Table Inheritance (JOINED)

In Joined Table Inheritance, each class in the inheritance hierarchy is mapped to its own table. The table of each subclass contains a foreign key to its parent class table, ensuring that the relationship between the entities is preserved.

How it works:

  • A separate table is created for each class in the hierarchy.
  • Subclass tables store only the fields that are specific to the subclass, and a foreign key links the subclass table to the parent table.
  • This strategy is more normalized but can result in more complex joins and potentially worse performance.

Example:

In this example:

  • Each entity (Vehicle, Car, Bike) is stored in its own table.
  • The **@Inheritance** annotation specifies the JOINED strategy.
  • The parent table (Vehicle) contains common fields (like id and model), while the subclass tables (Car and Bike) contain fields specific to those classes (like doors and hasPedals).
  • The foreign key in Car and Bike tables points to the Vehicle table.

The resulting tables might look like this:

Vehicle Table:

idmodel
1Sedan
2MTB

Car Table:

iddoors
14

Bike Table:

idhasPedals
2true

3. Table Per Class Inheritance (TABLE_PER_CLASS)

In Table Per Class Inheritance, each class in the hierarchy is mapped to its own table, and there is no foreign key relationship between the tables. All columns from the parent class are duplicated in the subclass tables, leading to less normalized data.

How it works:

  • Each class has its own table, and each table includes columns for the fields in the entire hierarchy (both parent and subclass fields).
  • This strategy avoids joins but can result in data redundancy.

Example:

In this example:

  • The Vehicle, Car, and Bike classes are mapped to separate tables.
  • Each subclass table contains the fields from both the parent class (Vehicle) and the subclass itself (Car or Bike).

The resulting tables might look like this:

Vehicle Table:

idmodel
1Sedan
2MTB

Car Table:

idmodeldoors
1Sedan4

Bike Table:

idmodelhasPedals
2MTBtrue

Conclusion

In JPA, inheritance can be mapped to the database using various strategies provided by the @Inheritance annotation. The three primary strategies are:

  • Single Table (SINGLE_TABLE): Stores all entities in the hierarchy in one table, with a discriminator column to distinguish the subclasses.
  • Joined (JOINED): Each class in the hierarchy is mapped to a separate table, with foreign keys linking subclasses to the parent class.
  • Table Per Class (TABLE_PER_CLASS): Each class in the hierarchy has its own table, with no foreign keys or shared columns.
  •  Each strategy has its advantages and trade-offs in terms of normalization, performance, and complexity, so choosing the right strategy depends on the specific needs of your application.
Similar Questions