Lazy loading was often an issue with JPA 2.0. You have to define at the entity if you want to use FetchType.LAZY (default) or FetchType.EAGER to load the relation and this mode is always used. FetchType.EAGER is only used if we want to always load the relation. FetchType.LAZY is used in almost all of the cases to get a well performing and scalable application.
But this is not without drawbacks. If you have to use an element of the relation, you need to make sure, that the relation gets initialized within the transaction that load the entity from the database. This can be done by using a specific query that reads the entity and the required relations from the database. But this will result in use case specific queries. Another option is to access the relation within your business code which will result in an additional query for each relation. Both approaches are far from perfect.
JPA 2.1 entity graphs are a better solution for it. The definition of an entity graph is independent of the query and defines which attributes to fetch from the database. An entity graph can be used as a fetch or a load graph. If a fetch graph is used, only the attributes specified by the entity graph will be treated as FetchType.EAGER. All other attributes will be lazy. If a load graph is used, all attributes that are not specified by the entity graph will keep their default fetch type.
Lets have a look how to define and use an entity graph.
The example entities
For this example we will use an order with a list of items and each item has a product. All relations are lazy.
The Order entity:
The OrderItem entity:
The Product entity:
Named entity graph
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) that have be loaded.
The following example shows the definition of the entity graph “graph.Order.items” which will load the list of OrderItem of an Order.
Now that we have defined the entity graph, we can use it in a query. Therefore we need to create a Map with query hints and set it as an additional parameter on a find or query method call.
The following code snippet shows how to use a named entity graph as a fetch graph in a find statement.
Named sub graph
We used the entity graph to define the fetch operation of the Order entity. If we want to do the same for the OrderItem entity, we can do this with an entity sub graph. The definition of a named sub graph is similar to the definition of an named entity graph and can be referenced as an attributeNode.
The following code snippets shows the definition of a sub graph to load the Product of each OrderItem. The defined entity graph will fetch an Order with all OrderItems and their Products.
What’s happening inside?
OK, from a development point of view entity graphs are great. They are easy to use and we do not need to write additional code to avoid lazy loading issues. But what is happening inside? How many queries are send to the database? Lets have a look at the hibernate debug log.
The log shows that only one query is created. Hibernate uses the entity graph to create a load plan with all 3 entities (Order, OrderItem and Product) and load them with one query.
We defined an entity graph that tells the entity manager to fetch a graph of 3 related entities from the database (Order, OrderItem and Product). The definition and usage of the entity graph is query independent and results in only one select statement. So the main drawbacks of the JPA 2.0 approaches (mentioned in the beginning) are solved.
From my point of view, the new entity graph feature is really great and can be a good way to solve lazy loading issues. What do you think about it? Please leave me a comment.
And if you want to learn more about the new JPA 2.1 features, have a look at my other articles:
- JPA 2.1 – How to implement a Type Converter
- JPA 2.1 Type Converter – The better way to persist enums
- Criteria Update/Delete – The easy way to implement bulk operations with JPA2.1