I noticed our "Get Order Details" API is executing 50 separate SQL queries to fetch the line items for 50 orders. This is the classic N+1 problem. While I can use JOIN FETCH in a custom HQL query, is there a more "Spring-native" way to handle this using @EntityGraph so I can reuse my existing repository methods?
3 answers
The @EntityGraph annotation is a great way to solve N+1 without writing messy HQL. You can define a named graph on your Entity or a dynamic one directly on your Repository method. By adding @EntityGraph(attributePaths = {"lineItems"}) above your findAll() method, Spring Data JPA will automatically perform a left join to fetch the related entities in a single query. I used this recently to optimize a dashboard that was taking 5 seconds to load; after implementing the graph, it dropped to under 400ms. Just be careful with "MultipleBagFetchException" if you try to fetch two different collection types (like Items and Tags) at the same time; Hibernate doesn't allow joining multiple "bags" in one query.
Does using the EntityGraph approach affect the "Lazy Loading" behavior of those entities globally, or does it only apply to the specific repository method where the annotation is used?
You can also use "Projections" if you only need a few fields. Fetching the whole Entity and its children is sometimes overkill if you're just building a summary table.
Kevin is right. Projections are even faster because they generate a "SELECT col1, col2" query instead of "SELECT *", which reduces the data transfer from the DB.
Christopher, it only applies to that specific method. The rest of your app will still respect the FetchType.LAZY setting you have on the entity fields. This is why Entity Graphs are so powerful—they allow you to be "Eager" only when you specifically need to be for a certain use case. It prevents you from having to change your global mapping and accidentally causing massive data fetches in other parts of the application where you only need the parent ID. It’s a very surgical way to optimize performance.