Lazy loading of relations between entities is a well established best practice in JPA. Its main goal is to retrieve only the requested entities from the database and load the related entities only if needed. That is a great approach, if we only need the requested entities. But it creates additional work and can be the cause of performance problems, if we also need some of the related entities.
Lets have a look at the different ways to trigger the initialization and their specific advantages and disadvantages.
1. Call a method on the mapped relation
Lets start with the most obvious and unfortunately also the most inefficient approach. We use the find method on the EntityManager and call a method on the relation.
2. Fetch Join in JPQL
A better option to initialize lazy relations is to use a JPQL query with a fetch join.
This tells the entity manager to fetch the selected entity and the relation within the same query. The advantages and disadvantages of this approach are obvious:
The advantage is that everything is fetched within one query. From a performance point of view, this is much better than the first approach.
And the main disadvantage is that we need to write additional code which executes the query. But it gets even worse, if the entity has multiple relations and we need to initialize different relations for different use cases. In this case we need to write a query for every required combination of fetch joined relations. This can become quite messy.
Using fetch joins in JPQL statements can require a huge number of queries, which will make it difficult to maintain the code base. So before we start to write lots of queries, we should think about the number of different fetch join combinations we might need. If the number is low, then this is a good approach to limit the number of performed queries.
3. Fetch Join in Criteria API
OK, this approach is basically the same as the one before. But this time we are using the Criteria API instead of the JPQL query.
4. Named Entity Graph
Named entity graphs are a new feature of JPA 2.1. It can be used to define a graph of entities that shall be queried from the database. The definition of an entity graph is done via annotations and is independent of the query. If you are not familiar with this feature, you can have a look at one of my former blog posts where I covered it in more detail.
The named entity graph can then be used by the find method of the EntityManager.
5. Dynamic Entity Graph
The dynamic entity graph is similar to the named entity graph and was also explained in one of the former posts. The only difference is, that the entity graph is defined via a Java API.
The definition via an API can be an advantage and a disadvantage. If we need lots of use case specific entity graphs, it might be better to define the entity graph within the specific Java code and to not add an additional annotation to the entity. This avoids entities with dozens of annotations. On the other hand, the dynamic entity graph requires more code and an additional method to be reusable.
So I recommend to use dynamic entity graphs, if we need to define a use case specific graph, that will not be reused. If we want to reuse the entity graph, it is easier to annotate a named entity graph.
Conclusion
We had a look at 5 different ways to initialize lazy relations. And as we have seen, each of them has its advantages and disadvantages. So what to remember from this article?
- Initializing a lazy relation via calling a method on a mapped relation causes an additional query. This should be avoided for performance reasons.
- Fetch joins in JPQL statements reduce the number of queries to one but we might need a lot of different queries.
- The Criteria API also supports fetch joins and we need specific code for each combination of relations that shall be initialized.
- Named entity graphs are a good solution, if we will reuse the defined graph in our code.
- Dynamic entity graphs can be the better solution, if we need to define a use case specific graph.
reference from http://www.thoughts-on-java.org/5-ways-to-initialize-lazy-relations-and-when-to-use-them/