Categories: Java, JPA

How to load nested JPA entities in a single query

jpa-fetch-joinsHave you ever realized that many times when accessing a managed entity’s attribute it’s common to see JPA performing many subsequent queries in the database in order to lazy load information? Well, it’s a good default behavior and works in the majority of the cases but still sometimes we need to modify this behavior on an ad hoc basis or per use case scenario. For these specific situations we can use a handy feature from JPA known as Fetch Joins. In a very abstract way we can say that the Fetch Joins allow us to dynamically define which relations we want to eagerly load when making a query. In this article we are going to retrieve nested JPA entities in a single query avoiding many database calls.

Example

Let’s consider the following example:

Our system has two entities: Customer and Address. The relationship between them is a bidirectional one-to-many from Customer to Address, which means that a Customer can have none or multiple instances of Address. 

These are our model classes

The persistence.xml containing some basic configuration about the database and model classes. In this example we are coding in a standalone Java application so this file needs to be accessible in the application classpath. For a default maven project we could use src.main.resources.META-INF.

Now let’s implement a class containing the “main” method that will be responsible for query all customers aged between 20 and 30 years. Then, once we have the list of customers, we will access its attribute “addresses”, forcing the JPA to make additional queries to load the collection of addresses per customer.

It’s important to notice on the above code that we used the CriteriaQuery’s DSL to create our JPA query but it can be made in many other ways, like using named queries.

Our example code will produce the following output:

As we can see in the log JPA performed 1 query to retrieve the customers aged between 20 and 30 years and then, for each customer, executed another database query to load the addresses. In this example we just have 10 customers so it generates 11 queries. Within this scenario we will have always N (number of customers) + 1 database queries being performed.

The solution

Now let’s modify our code just a little bit to dynamically instruct JPA to eagerly load the addresses collection within the same query. Pay a special attention to the highlighted line, it will be the only line modified in the FetchJoinExample class.

Our example code will now produce the following output:

No more multiple additional queries for getting the customers’ addresses. Everything loaded by the same main query.

Conclusion

We’ve only scratched the surface of the JPA Fetch Joins but the main idea was to introduce you to this very useful feature. Notice that fetch too much data in a single query can cause you more problems than have multiple database calls so you need to understand your scenario and then define the best approach.

Article info