In this new article about Entity Graph with JPA in Spring Boot, we will explore how to improve our queries and enhance application performance. If you want to expand your knowledge about queries with Spring Boot, you can check out this article on Criteria Queries in Spring Data.
Entity Graph usage is sometimes unfamiliar among developers using JPA in their applications. Version 2.1 introduced this feature and allows us to define a template to retrieve all the persisted and related fields we want from our database.
How does Entity Graph work in JPA?
Before Entity Graph in JPA, we had to use FetchType.LAZY or FetchType.EAGER to load our collections. This often resulted in n+1 queries when using LAZY, where data is loaded as needed.
JPA introduced this feature to improve query performance when dealing with associated collections. Essentially, JPA loads the entire graph to execute a single query, avoiding the queries for associated relationships.
Example of Entity Graph in JPA:
Create the model:
Let’s start by creating the model for our example:
@Getter @Setter @Entity public class Car { @Id private Long id; private String color; private String model; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn private User user; }
@Entity @Getter @Setter public class User { @Id private Long id; private String name; private String email; @OneToMany(mappedBy = "car") private List<Car> cars = new ArrayList<>(); }
We have defined two tables that are related to each other through a one-to-many relationship with a FetchType LAZY. Note that we have two strategies for collections:
- EAGER: Loads associated relationships. The @Basic, @ManyToMany, and @OneToOne relationships behave like this by default.
- LAZY: Loads when accessed. This is the default behavior for @OneToMany, @ManyToMany, and @ElementCollection.
Result with LAZY relationship without Entity Graph:
If we run the code as it is, we will face the problem of n+1 queries. In our case, three queries will be executed: one to obtain the users and two more for each group of cars. The more data we have, the more queries will be executed, leading to poorer performance. Let’s improve it using Entity Graph.
select user0_.id as id1_1_, user0_.email as email2_1_, user0_.name as name3_1_ from user user0_ where user0_.name=? select user0_.id as id1_1_, user0_.email as email2_1_, user0_.name as name3_1_ from user user0_ where user0_.name=?
Define an Entity Graph
To define an Entity Graph, we will use the @NamedEntityGraph
annotation, which allows us to specify the attributes we want to load in the entity and its relationships.
@NamedEntityGraph( name = "user-entity-graph", attributeNodes = { @NamedAttributeNode("name"), @NamedAttributeNode("email"), @NamedAttributeNode("cars"), } ) @Entity @Getter @Setter public class User { @Id private Long id; private String name; private String email; @OneToMany(mappedBy = "car") private List<Car> cars = new ArrayList<>(); }
Activate Entity Graph in the Repository
@Repository public interface UserRepository extends CrudRepository<User, Long> { @EntityGraph(value = "user-entity-graph", type = EntityGraphType.LOAD) List<User> findByName(String name); }
Add @EntityGraph
to the query in which you want it to be activated in the repository.
Result with LAZY relationship using Entity Graph
By running the same application with this small change, you will see that the result is a single query that functions as a join, significantly improving the time and performance.
select user0_.id as id1_1_0_, cars1_.id as id1_0_1_, user0_.email as email2_1_0_, user0_.name as name3_1_0_, cars1_.color as color2_0_1_, cars1_.model as model3_0_1_, cars1_.user_id as user_id4_0_1_, cars1_.user_id as user_id4_0_0__, cars1_.id as id1_0_0__ from user user0_ left outer join car cars1_ on user0_.id=cars1_.user_id where user0_.name=?
Conclusion
When developing an application that accesses a database, query response times are crucial. Therefore, the queries we perform must be as optimal as possible, which is why the use of Entity Graph with JPA in Spring Boot.
If you need more information, you can leave us a comment or send an email to refactorizando.web@gmail.com You can also contact us through our social media channels on Facebook or twitter and we will be happy to assist you!!