Skip to content
SimplyMe
Go back

Taming the Lazy Beast: Reactive DTOs and Hibernate Relationships in Quarkus

Edit page

Building reactive applications with Quarkus and Hibernate Reactive is a fantastic way to achieve high performance and responsiveness. However, you’ll inevitably encounter the “lazy loading” challenge when dealing with entity relationships and Data Transfer Objects (DTOs). This post will guide you through the common pitfalls and provide practical solutions to ensure smooth data flow in your reactive Quarkus applications.

The Lazy Loading Conundrum

Hibernate, by default, employs lazy fetching for related entities. This means that related data is only loaded when you explicitly access it. While this conserves resources in many scenarios, it can lead to problems in reactive environments:

Why does this happen in Reactive Contexts?

Reactive programming is about non-blocking operations. When you use Uni and Multi you are creating a stream of data that will be processed asynchronously. The Hibernate session may close before the lazy loaded relationships are accessed.

Conquering the Lazy Beast: Practical Solutions

Here’s how to tackle lazy loading and ensure your DTOs are populated correctly in your reactive Quarkus applications:

1. Explicit Fetching with JPQL or Criteria API (The Recommended Approach)

This approach provides the most control and performance benefits. By explicitly fetching related entities in your queries, you guarantee that the necessary data is loaded before the reactive stream completes.

public Uni<List<MyDTO>> findMyDTOsWithRelations() {
  return getEntityManager()
      .createQuery(
          "SELECT DISTINCT e FROM MyEntity e JOIN FETCH e.relatedEntity",
          MyEntity.class)
      .getResultList()
      .map(myEntities
          -> myEntities.stream()
                 .map(myEntity
                     -> new MyDTO(myEntity.name,
                         myEntity.relatedEntity
                             .relatedName) // Example of accessing the related
                                           // entity.
                     )
                 .collect(Collectors.toList()));
}

2. DTO Projection with Joins

Leverage Panache’s projection capabilities to directly retrieve related data into your DTOs using joins.

public Uni<List<MyDTO>> findMyDTOsWithRelationsProjection() {
  return find(
      "SELECT e.name, r.relatedName FROM MyEntity e JOIN e.relatedEntity r")
      .project(MyDTO.class)
      .list();
}

3. Eager Fetching (Use with Caution)

You can change the fetching strategy to eager fetching using annotations like @ManyToOne(fetch = FetchType.EAGER).

4. Manual DTO Population

For more complex scenarios, retrieve the main entity and related entities in separate reactive calls, then combine the results into your DTO.

Key Considerations

In Conclusion

By understanding the challenges of lazy loading and adopting the appropriate solutions, you can build robust and efficient reactive Quarkus applications that seamlessly handle entity relationships and DTOs. Remember that explicit fetching and projections offer the best balance of performance and control. Happy coding!


Edit page
Share this post on:

Previous Post
UUIDs vs. ULIDs in Hibernate: Choosing the Right ID Generator
Next Post
Mengonfigurasi Listener Oracle Database Standard Edition dengan Bind ke 0.0.0.0