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:
Vehicle
is the superclass containing common attributes (likeid
andmodel
).Car
andBike
are subclasses that extendVehicle
and contain specific attributes (doors
forCar
andhasPedals
forBike
).- 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
Vehicle
table contains the common fields (id
andmodel
). - The
Car
andBike
tables store subclass-specific attributes (doors
andhasPedals
). - The
Car
andBike
tables both reference theVehicle
table via theid
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.