How do you implement JOINED inheritance in JPA?

Table of Contents

Introduction

In Java Persistence API (JPA), inheritance strategies define how entities in a class hierarchy are mapped to database tables. One of the commonly used strategies for this mapping is the JOINED strategy. The JOINED inheritance strategy involves creating separate tables for the superclass and each subclass. This strategy ensures that the data is normalized, with each table storing only the fields relevant to that specific entity class. Subclasses are linked to the superclass via foreign keys, ensuring referential integrity.

While the JOINED strategy promotes better database normalization and avoids data duplication, it may result in additional joins when querying related entities, which can impact performance in certain scenarios.

The Role of the JOINED Inheritance Strategy

The JOINED inheritance strategy maps each class in the inheritance hierarchy to its own table. The superclass table stores the common attributes shared by all subclasses, while the subclass tables store their specific attributes. A foreign key is created in the subclass table, referencing the primary key of the superclass table. When retrieving data, a JOIN operation is performed between the superclass and subclass tables.

Key Features of JOINED Strategy:

  1. Separate Tables: Each class in the inheritance hierarchy has its own table, which reduces data redundancy and promotes better normalization.
  2. Foreign Key Relationship: Subclasses contain a foreign key that references the primary key of the superclass table, maintaining referential integrity.
  3. Join Operations: Queries often involve joins between the superclass and subclass tables to fetch the complete entity data, which may affect performance compared to the SINGLE_TABLE strategy.

Advantages of JOINED Strategy:

  1. Normalization: The database schema is more normalized compared to the SINGLE_TABLE strategy. Each table contains only the columns relevant to that class, reducing data duplication.
  2. Maintainability: The schema is easier to maintain and extend since each class has its own table, and new subclasses can be added without affecting existing data.
  3. Flexible Queries: JOINED inheritance supports flexible queries that can easily retrieve superclass or subclass data independently, making it suitable for more complex object models.

Disadvantages of JOINED Strategy:

  1. Performance Overhead: Queries often require JOIN operations to combine data from multiple tables (superclass and subclass), which can lead to performance overhead, especially with large datasets or complex queries.
  2. Complex Queries: Since data is spread across multiple tables, queries to retrieve complete objects may become more complex, requiring explicit joins or additional fetch strategies.

How to Implement JOINED Inheritance in JPA

To implement the JOINED inheritance strategy in JPA, you need to use the @Inheritance annotation with strategy = InheritanceType.JOINED. The superclass will contain common attributes, and each subclass will contain its specific attributes, with a foreign key referencing the superclass.

Here's how to configure the JOINED inheritance strategy in JPA:

Example:

1. Define the Superclass Entity

The superclass contains common attributes for all entities in the hierarchy. It is marked with the @Inheritance annotation and specifies the JOINED strategy.

2. Define the Subclass Entities

Each subclass will have its own table containing specific attributes. The @Entity annotation marks these as entities, and they are automatically linked to the Vehicle table via a foreign key.

In this example:

  • Vehicle is the superclass containing common attributes (like id and model).
  • Car and Bike are subclasses that extend Vehicle and contain specific attributes (doors for Car and hasPedals for Bike).
  • The @Inheritance(strategy = InheritanceType.JOINED) annotation specifies that the JOINED strategy should be used.

3. Resulting Database Schema

Using the JOINED inheritance strategy, JPA will generate separate tables for Vehicle, Car, and Bike, with the following structure:

Vehicle Table:

idmodel
1Sedan
2MTB

Car Table:

iddoors
14

Bike Table:

idhasPedals
2true

In this schema:

  • The Vehicle table contains the common fields (id and model).
  • The Car and Bike tables store subclass-specific attributes (doors and hasPedals).
  • The Car and Bike tables both reference the Vehicle table via the id field (foreign key).

When querying for a Car or Bike, a JOIN is required to fetch both the superclass and subclass data. For example:

4. Query Example with JOIN

When querying data, you can use JPQL or native SQL to join the superclass and subclass tables. Here's an example using JPQL to fetch a Car along with its Vehicle attributes:

This query joins the Vehicle table with the Car table to retrieve both the Vehicle and Car data.

Conclusion

The JOINED inheritance strategy in JPA is a normalized approach for mapping a class hierarchy to relational database tables. It stores each class in its own table and links them through foreign key relationships. While this strategy promotes database normalization and maintainability, it can lead to performance overhead due to the need for joins when querying data.

This strategy is suitable when:

  • You need a normalized schema with separate tables for each class.
  • You want to avoid data duplication in the database.
  • You can tolerate the performance cost of JOIN operations when querying related entities.

By using the @Inheritance(strategy = InheritanceType.JOINED) annotation, you can implement JOINED inheritance in JPA and maintain a clean, normalized database schema. However, if performance is a critical concern, especially with complex queries or large data sets, other inheritance strategies like SINGLE_TABLE may be worth considering.

Similar Questions