Hibernate Table Per Class inheritance mapping

Table per class is one of three strategies in JPA that persist Java domain model into relational database. It is the least used one than others. Let’s find out why this strategy is avoided, even ifits features may be useful in some cases.

Model

Here are Java classes with JPA mappings:

@Entity
@Table(name = "PRODUCT")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 
public class Product {
 
    @Id
    @GeneratedValue
    private Long id;
 
    private String name;
 
    //Getters and setters
} 
@Entity
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). And this is the only information which we should provide – the strategy don’t need a discriminator column, subclasses don’t need any specific configuration – even setting discriminator values by the @DiscriminatorValue annotation.

Similarly to the Joined Strategy (desribed here), each non abstract class of the hierarchy gives its own table. But the table of the corresponding entity contains all the fields of this entity, including the inherited ones. All tables are independent – there are no foreign keys between them. In our example, we get three tables: PRODUCT (with columns: ID, NAME), CAR (with columns: ID, NAME, BRAND, MODEL), and TOY (with columns: ID, NAME, MINIMALAGE). As a consequence, the tables don’t need to store discriminator values.

To instantiate a particular entity, we have to query only one table.

Pros

The strategy offers good performane when querying single entities – we have all the data in one table, we don’t need any joins.

Having individual table per entity allows us to define specyfic constraints at the database level to control data integrity.

Cons

The main drawback of the strategy is the fact we can’t use polimorphic queries efficiently. When querying parent entities, we have to use UNION statements to gather data from all tables.

Another aspect is that data in tables are not normalized – the same information can be stored in different tables. Controling the same logic of data integrity together in many tables can be error prone.

Especially defining relationships of the entities can be very confusing – imagine our appliaction has the following entity:

@Entity
public class Customer extends Product {
    @Id
    @GeneratedValue
    private Long id;
    private Product product;
} 

We can’t efficiently define foreign key constraint (from customer to product) at the database level, beacuse foreign key can’t point to more than one table. The only solution is not to define such key and control data only at the application level. We don’t recommend this solution – it can lead to loss of data integrity

Furthermore, although the Table Per Class strategy is part of the JPA , the support for this startegy is optional – providers aren’t forced to implement this solution. As a consequence, the solution based on this strategy isn’t portable.

Summary

As we can see, the Table Per Class strategy have more disadvantages than advantages. It makes it difficult for us to control data integrity at the database level, performance of polymorphic queries can be really low and our solution isn’t portable across different JPA providers. so, when we develop application that is changing dynamically, the Table Per Class should’t be chosen.

But there can be some cases, when this strategy is the best choice – when the Java model isn’t complicated (for example subclasses doesn’t share common fields and have different characteristics) and we are sure the will be no modifications of the entities hierarchy, we can choose this strategy as the most efficient.