How do you implement JOINED inheritance in JPA?
Table of Contents
- Introduction
- The Role of the JOINED Inheritance Strategy
- How to Implement JOINED Inheritance in JPA
- Conclusion
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:
- Separate Tables: Each class in the inheritance hierarchy has its own table, which reduces data redundancy and promotes better normalization.
- Foreign Key Relationship: Subclasses contain a foreign key that references the primary key of the superclass table, maintaining referential integrity.
- 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:
- 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.
- 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.
- 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:
- 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.
- 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:
Vehicleis the superclass containing common attributes (likeidandmodel).CarandBikeare subclasses that extendVehicleand contain specific attributes (doorsforCarandhasPedalsforBike).- 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:
| id | model |
|---|---|
| 1 | Sedan |
| 2 | MTB |
Car Table:
| id | doors |
|---|---|
| 1 | 4 |
Bike Table:
| id | hasPedals |
|---|---|
| 2 | true |
In this schema:
- The
Vehicletable contains the common fields (idandmodel). - The
CarandBiketables store subclass-specific attributes (doorsandhasPedals). - The
CarandBiketables both reference theVehicletable via theidfield (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.