How do you configure inheritance strategies in JPA?
Table of Contents
Introduction
Inheritance in Java is a fundamental concept that allows one class (the subclass) to inherit attributes and methods from another class (the superclass). In Java Persistence API (JPA), inheritance strategies define how to map Java class hierarchies to relational database tables. JPA provides several strategies for inheritance, and configuring them correctly is essential for effective object-relational mapping (ORM).
The @Inheritance
annotation in JPA allows you to configure inheritance mapping for your entity classes. This annotation specifies how the subclass entities (derived classes) should be stored in the database in relation to their parent (superclass) entities. Depending on your application's requirements, you can choose between three primary inheritance strategies: SINGLE_TABLE, JOINED, and TABLE_PER_CLASS.
In this guide, we'll walk through how to configure each inheritance strategy in JPA.
Configuring Inheritance Strategies in JPA
1. SINGLE_TABLE Strategy
The SINGLE_TABLE inheritance strategy maps all entities in the hierarchy (both the superclass and subclasses) to a single table. A discriminator column is used to differentiate between the various entity types. This is the most performance-efficient strategy for reading entities, but it may lead to sparse tables if the subclasses have significantly different attributes.
Configuration:
To configure the SINGLE_TABLE strategy in JPA, use the @Inheritance
annotation with strategy = InheritanceType.SINGLE_TABLE
. You should also define a discriminator column using the @DiscriminatorColumn
annotation, which identifies which subclass each row in the table corresponds to.
Example:
In the example above:
Vehicle
is the superclass.Car
andBike
are subclasses.- The
@DiscriminatorColumn
annotation creates a column (vehicle_type
) to distinguish betweenCar
andBike
entities.
Table Example:
id | model | vehicle_type | doors | hasPedals |
---|---|---|---|---|
1 | Sedan | CAR | 4 | NULL |
2 | MTB | BIKE | NULL | true |
2. JOINED Strategy
The JOINED strategy creates a separate table for each class in the inheritance hierarchy. The subclass tables contain only the fields specific to that class, while the superclass table holds the common attributes. Subclasses have a foreign key that references the primary key of the superclass. This strategy provides better normalization but may introduce additional overhead due to the need for joins when querying data.
Configuration:
To configure the JOINED strategy, use the @Inheritance
annotation with strategy = InheritanceType.JOINED
.
Example:
In this configuration:
- The
Vehicle
table stores common fields likeid
andmodel
. - The
Car
andBike
tables store only their respective fields, with each having a foreign key to theVehicle
table.
Table Examples:
Vehicle Table:
id | model |
---|---|
1 | Sedan |
2 | MTB |
Car Table:
id | doors |
---|---|
1 | 4 |
Bike Table:
id | hasPedals |
---|---|
2 | true |
3. TABLE_PER_CLASS Strategy
The TABLE_PER_CLASS strategy maps each class in the hierarchy to its own table. The table for each class includes both the inherited and subclass-specific attributes. This strategy does not use joins but can lead to data duplication if the subclass tables have common fields. It is typically used when the subclasses are completely independent and don't share much behavior.
Configuration:
To configure the TABLE_PER_CLASS strategy, use the @Inheritance
annotation with strategy = InheritanceType.TABLE_PER_CLASS
.
Example:
In this configuration:
- The
Vehicle
table is not explicitly required. Each subclass (Car
andBike
) has its own table with both its own and the inherited fields.
Table Examples:
Vehicle Table (Not Required): This table doesn't exist because each subclass has its own table.
Car Table:
id | model | doors |
---|---|---|
1 | Sedan | 4 |
Bike Table:
id | model | hasPedals |
---|---|---|
2 | MTB | true |
Conclusion
Configuring inheritance strategies in JPA is essential for mapping class hierarchies to relational database tables in a way that matches your application's data modeling needs. Each inheritance strategy has its own trade-offs in terms of performance, normalization, and ease of querying:
- SINGLE_TABLE is efficient for querying but may lead to sparse tables.
- JOINED provides normalized data at the cost of more complex queries due to joins.
- TABLE_PER_CLASS avoids joins but may lead to data duplication and is less efficient in some scenarios.
By using the @Inheritance
annotation with the appropriate strategy, you can choose the best approach for your application's specific requirements.