JPA Pitfalls (5): Object-Relational Mapping and Inheritance

This blog article is part of a “series of blog articles” about common pitfalls using JPA and ways to avoid them. In this article, we describe possible performance impacts of JPA inheritance mapping strategies.

JPA supports three inheritance mapping strategies:

  • SINGLE_TABLE
  • JOINED
  • TABLE_PER_CLASS.

This blog post describes the databases tables for the three inheritance mapping strategies using the following class model with two superclasses Person and Employee and three subclasses FullTimeEmployee, PartTimeEmployee and ExternalEmployee.

Sample object model
  • SINGLE_TABLE

The strategy SINGLE_TABLE stores all instances of an inheritance hierarchy in a single table. Fields not part of the concrete class are left empty.

Database tables SINGLE_TABLE strategy

The strategy SINGLE_TABLE is the default, if there is no strategy specified. In most cases the strategy SINGLE_TABLE has in the best performance. There is a small drawback: columns for attributes declared in sibling other classes of the hierarchy include NULL values. So these columns need to be nullable although they might not be null in the object model. 

  • JOINED

The JOINED strategy normalizes the database tables, meaning each class has its own table including the columns for the fields declared in that class.

Database tables JOINED strategy

The JOINED strategy results in many join operations when loading instances. In the above example there are separate tables for Person, Employee and the three Employee subclasses. So the SELECT statement loading a FullTimeEmployee instance need to join the Person, the Employee and the FullTimeEmployee table.

This strategy should be used when most of the instances are of type Person or Employee. Then the instances occupy less space in the database compared to SINGLE_TABLE, because no NULL values are stored for attributes of other classes in the hierarchy.

  • TABLE_PER_CLASS

With the TABLE_PER_CLASS strategy each concrete subclass gets its own table with columns for all the fields of the class including the inherited fields.

Database tables TABLE_PER_CLASS strategy

The TABLE_PER_CLASS strategie may result in poor performance when using JPQL queries over the superclass Person, because it might result in UNION SQL queries. The same holds true for navigating a relationship to the superclass of an inheritance with TABLE_PER_CLASS strategy. The related instance is stored in one of several tables.

This strategie should be used if the superclasses Person and Employee are abstract and if the application does not treat the instances of the concrete subclasses as Person or Employee.

Recommendation: Try the SINGLE_TABLE inheritance strategy first.

You can find an example of this pitfall and its solution in the classes JoinedInheritanceStrategyExperiment and TablePerClassInheritanceStrategyExperiment in this project: https://github.com/akquinet/jpapitfalls.git.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.