BLOG
26 September 2017

No More LazyInitializationException – Use JPA 2.1 Entity Graph

tech

Until JPA 2.0, we were restricted to use pretty static way of querying entities by declaring FetchType.LAZY (default) or FetchType.EAGER on entity’s associations – once selected mode is always used.

FetchType.EAGER is a good choice if we always want to load a related entity. The issue of this approach is its performance. Another way is to use FetchType.LAZY but we are obligated to remember each time to perform particular query within a transaction to load relations from the database when we want to use them.

If we do not want to prepare a specific query, we have to access the relations from business code, but it will end up with an additional query for each entity that was not queried before. Since JPA 2.1 we have got a new feature called Entity Graphs that provides us with a sophisticated way of querying associated objects.

Entity Graphs give us a possibility to define fetch plans and declare which relations (attributes) have to be queried from the database. It is possible to choose two types of graphs: fetch or load graph. Fetch graph treats all specified associations (attributes) as FetchType.EAGER, all others will be lazy. Load graph treats all not specified associations (attributes) with their default fetch type.

Fascinating? Let’s check how it works and compare codes with Criteria API and Named Queries.

Database schema

To test our queries, let’s prepare sample model with relationships as shown below.

We will use five entities: Company, Department, Employee, Address and Car. The FetchType of all these relations is FetchType.LAZY, so the entity manager will not fetch them from the database by default and will initialize them with a proxy instead.

Sample app

Since we are testing graph structure of data, the best choice to visualise relationships would be to see our results in JSON format. For this purpose, let’s write simple Spring application with the REST API.

To show different approaches of querying data, we prepared interface CompanyService:

This interface will be implemented by three types of querying services with JPA:

  • CompanyServiceCriteriaAPIImpl
  • CompanyServiceNamedQueryImpl
  • CompanyServiceEntityGraphImpl

Above interface will be injected by Spring to our REST controller like below:

By @Qualifier we can steer which implementation we want to choose for our tests.

We are going to perform tests with curl by invoking:

Before Entity Graph…

Before we start querying data with Entity Graph, let’s see how we have done it before. Let’s query particularCompanywithallrelatedDepartments, so we are going to implement getCompanyWithDepartments method.

With Criteria API we have to build CriteriaQuery and fetch departments association:

In a case of Named Query, we have to define @NamedQuery with JPQL query at the entity, and after that, we need to build JOIN FETCH for associations:

Then, we need to invoke this query:

Named Entity Graph

Now we are going to implement it with a new mechanism of JPA 2.1. The definition of a named entity graph is done by the @NamedEntityGraph annotation at the entity. It defines a unique name and a list of attributes (the attributeNodes) which need to be loaded.

As you can see, we just listed attributes (relationships) that need to be queried. In above annotation we have defined entity graph, so now we can use it in a query. We have to create a Map with query hints and set it as an additional parameter on a find or query method call. Below code shows how we can use an entity graph as a fetch graph in a find method.

The result of all above queries is the same and looks like:

no-more-laziness-quote

Query for sub-graph

In next example let’s query for particular Company with all related departments and all relevant employees, so we are going to implement a getCompanyWithDepartmentsAndEmployees method.

With Criteria API we have to create CriteriaQuery, fetch departments attribute and then fetch employees attribute from it:

With Named Query, we need to define JPQL query, fetch departments, employees:

Then, we need to invoke our query:

Named subgraph

For querying company with all departments, we had to define @NamedEntityGraph, but if we want to query relationships from Department, we have to define Company entity subgraph @NamedSubgraph. The definition of a named subgraph is similar to the definition of a named entity graph and can be referenced as an attributeNode.

The following code shows usage of subgraph:

Invocation of above query looks like:

The result of all above queries is the same and looks like:

Dynamic Entity Graph

Besides static graph queries, it is possible to implement dynamic entity graph. We will define simple entity graph that tells the entity manager to fetch Company with all associated Cars.

We have to use the createEntityGraph(Class rootType) method of the entity manager to create an entity graph for the Company entity and in next step define a list of attributes to be fetched. Our dynamic query looks like:

The result is:

Conclusion

Entity Graph seems to be an additional mechanism that helps to create an independent and high level of database queries in just one selection. It also provides a flexible approach of loading the associations and attributes of entities.

It could help to improve the performance of your application and solve lazy loading issues in the pretty elegant way. Also, dynamic entity graphs give you a possibility to define fetch strategy even at runtime, for example, based on your method parameters.

If you are interested, you can find all source codes here.



Author
Adam Zaręba
Software Developer

Java developer. Passionate about all kinds of backend technologies and EAI middlewares. Co-founder of Java User Group Białystok. Fan of Dragon Ball and Sicilian mafia movies