How do you implement multi-table inheritance in JPA?

Table of Contents

Introduction

In JPA (Java Persistence API), inheritance allows you to model relationships between entity classes that share common attributes. When you have a class hierarchy where subclasses share some common fields and behaviors but also have their own distinct attributes, you can use multi-table inheritance strategies to map these relationships to database tables.

In JPA, multi-table inheritance means that the fields of a superclass and its subclasses are mapped across multiple tables in the database. This is in contrast to a single-table inheritance approach, where all fields from the superclass and subclasses are stored in one table.

JPA provides three main inheritance strategies to manage multi-table inheritance:

  1. Single Table Inheritance (**SINGLE_TABLE**): All entities are mapped to a single table, with a discriminator column to differentiate between the types.
  2. Joined Table Inheritance (**JOINED**): Each entity in the hierarchy is mapped to its own table, with a shared base table that stores the common attributes.
  3. Table Per Class Inheritance (**TABLE_PER_CLASS**): Each entity in the hierarchy is mapped to its own table, without a shared base table.

In this article, we'll look at how to implement multi-table inheritance in JPA using these strategies.

Inheritance Strategies in JPA

1. Single Table Inheritance (**SINGLE_TABLE**)

In single-table inheritance, all entities in the hierarchy are stored in a single table. The table will have a discriminator column that determines which subclass an entity belongs to. This strategy is efficient in terms of database queries but may result in sparse tables if subclasses have many unique fields.

Example: Single Table Inheritance

Explanation:

  • Discriminator Column: The @DiscriminatorColumn annotation specifies the column used to distinguish between different entity types (e.g., entity_type).
  • Discriminator Value: The @DiscriminatorValue annotation is used to specify the value for each subclass in the entity_type column. In this example, Dog and Cat will have different discriminator values.

Database Schema:

2. Joined Table Inheritance (**JOINED**)

In joined-table inheritance, each class in the hierarchy (including the superclass and subclasses) is mapped to a separate table. The common attributes of all entities are stored in a base table, and each subclass has its own table. The tables are joined using the primary key of the superclass.

Example: Joined Table Inheritance

@Entity public class Dog extends Animal {    private boolean isVaccinated;    // Getters and setters }

Explanation:

  • Inheritance Type: The @Inheritance(strategy = InheritanceType.JOINED) annotation specifies that the JOINED inheritance strategy should be used.
  • Table Structure:
    • The Animal class will be mapped to one table.
    • The Dog and Cat classes will be mapped to separate tables with a foreign key to the Animal table.

Database Schema:

3. Table Per Class Inheritance (**TABLE_PER_CLASS**)

In the table-per-class inheritance strategy, each class in the inheritance hierarchy is mapped to a separate table, but unlike the JOINED strategy, there is no base table. Each subclass has its own table, and there is no shared primary key between tables. This means that data redundancy can occur, but queries can be more efficient for subclasses since there’s no need for joins.

Example: Table Per Class Inheritance

Explanation:

  • Inheritance Type: The @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) annotation specifies the TABLE_PER_CLASS inheritance strategy.
  • Table Structure:
    • Each subclass (Dog and Cat) has its own table, and there is no base table for the common attributes.
    • There is data duplication because each table contains its own copy of the fields from the parent class.

Database Schema:

Comparison of Inheritance Strategies

FeatureSINGLE_TABLEJOINEDTABLE_PER_CLASS
Number of Tables1 (all entities in a single table)3 (base table + 1 table for each subclass)2 or more (1 table per subclass)
EfficiencyFast for reads (no joins required)Slower due to join operationsSlower for reads (no joins, but more tables)
Data RedundancyLess redundancyNo redundancy, shared attributes in base tableMore redundancy (each subclass has its own table)
FlexibilityLess flexible, harder to extendMore flexible, better for complex hierarchiesCan be inefficient due to duplication of columns
Use CaseBest for simpler hierarchiesBest for complex hierarchies with shared attributesBest for independent entities with little shared data

Conclusion

In JPA, implementing multi-table inheritance can be done using the SINGLE_TABLE, JOINED, and TABLE_PER_CLASS inheritance strategies. Each strategy has its own use cases, trade-offs, and performance implications:

  • Single Table Inheritance is best suited for simple hierarchies and provides the best performance for querying all entities in the hierarchy.
  • Joined Table Inheritance is ideal when you want to normalize the database schema and avoid data redundancy, at the cost of additional joins in queries.
  • Table Per Class Inheritance is useful when you want each entity to have its own table, but it can lead to data duplication and inefficiency in complex hierarchies.

By choosing the appropriate inheritance strategy for your application, you can ensure that your database schema aligns with your domain model and provides efficient persistence for your entities.

Similar Questions