Hibernate Joined Table inheritance mapping

Joined Table is one of three strategies in JPA dealing with persisting Java domain model into relational database. The main point of this strategy is that each class of the hierarchy have its own table. Let’s check how to use this strategy and what are the consequences of using this solution.

Model

Here are Java classes with JPA mappings:

@Entity
@Table(name = "PRODUCT")
@Inheritance(strategy = InheritanceType.JOINED) 
@DiscriminatorColumn(name="type") 
public class Product {
 
    @Id
    @GeneratedValue
    private Long id;
    private String name;

    //Getters and setters
} 
@Entity
@DiscriminatorValue("Car") 
public class Car extends Product {
    private int brand;
    private int model; 
} 
@Entity
public class Toy extends Product {
    private int minimalAge;
}  

We must explicitly define the strategy in @Inheritance annotation at the root entity, because the default is Single Table strategy (described here). Subclasses don’t need any specific configuration – if we don’t want to use default discriminator values, we can customize them using @DiscriminatorValue annotation.

The behavior of this strategy is very intuitive – each class of the hierarchy gives its own table. Each table contains only the primary key of the entity and fields of this corresponding class. To instantiate a particular entity, we have to query all the tables that exist in the hierarchy of this entity. Only the root table contains additional column with discriminator value – based on this information we know which tables we must to query.

Pros

From the point of view of the database, the Joined inheritance strategy is is the most consistent of all three strategies – there are no redundancy in data persistence. We can define not null checks and other constraints on all the columns to control data integrity at the database level.

The fact that we don’t have nullable columns while persisting entity (like in Single Table strategy ) has the positive impact on the amount of memory used by the database – the database use the minimum amount of memory needed to store entity.

Cons

Due to the fact, that entity is stored in few tables, we have to use joins to read the whole object. In our example, while querying the Car entity, the query would look like:

SELECT p.ID, p.NAME, c.BRAND, c.MODEL 
FROM PRODUCT p 
    LEFT JOIN CAR c 
        ON p.ID = c.ID
WHERE p.TYPE = 'Car';

The amount of joins in query grows proportionally to the amount of classes in the hierarchy of the entity. This can have a negative impact on the performance of reading entities.

Summary

The Joined strategy should be chosen, when data integrity is more important than performance, when there is a strong need to control data at the database level.

But when you expect to have many polymorphic queries, this strategy isn’t a good choice.