eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

1. Overview

JPA 2.1 has introduced the Entity Graph feature as a more sophisticated method of dealing with performance loading.

It allows defining a template by grouping the related persistence fields which we want to retrieve and lets us choose the graph type at runtime.

In this tutorial, we’ll explain in more detail how to create and use this feature.

2. What the Entity Graph Tries to Resolve

Until JPA 2.0, to load an entity association, we usually used FetchType.LAZY and FetchType.EAGER as fetching strategiesThis instructs the JPA provider to additionally fetch the related association or not. Unfortunately, this meta configuration is static and doesn’t allow switching between these two strategies at runtime.

The main goal of the JPA Entity Graph is then to improve the runtime performance when loading the entity’s related associations and basic fields.

Briefly put, the JPA provider loads all the graphs in one select query and then avoids fetching associations with more SELECT queries. This is considered a good approach for improving application performance.

3. Defining the Model

Before we start exploring the Entity Graph, we need to define the model entities we’re working with. Let’s say we want to create a blog site where users can comment on and share posts.

So, first, we’ll have a User entity:

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;

    //...
}

The user can share various posts, so we also need a Post entity:

@Entity
public class Post {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String subject;
    @OneToMany(mappedBy = "post")
    private List<Comment> comments = new ArrayList<>();

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn
    private User user;
    
    //...
}

The user can also comment on the shared posts, so, finally, we’ll add a Comment entity:

@Entity
public class Comment {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String reply;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn
    private Post post;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn
    private User user;
    
    //...
}

As we can see, the Post entity has an association with the Comment and User entities. The Comment entity has an association to the Post and User entities.

The goal is then to load the following graph using various ways:

Post  ->  user:User
      ->  comments:List<Comment>
            comments[0]:Comment -> user:User
            comments[1]:Comment -> user:User

The FetchType method defines two strategies for fetching data from the database:

  • FetchType.EAGER: The persistence provider must load the related annotated field or property. This is the default behavior for @Basic, @ManyToOne, and @OneToOne annotated fields.
  • FetchType.LAZY: The persistence provider should load data when it’s first accessed, but can be loaded eagerly. This is the default behavior for @OneToMany, @ManyToMany and @ElementCollection-annotated fields.

For example, when we load a Post entity, the related Comment entities are not loaded as the default FetchType since @OneToMany is LAZY. We can override this behavior by changing the FetchType to EAGER:

@OneToMany(mappedBy = "post", fetch = FetchType.EAGER)
private List<Comment> comments = new ArrayList<>();

By comparison, when we load a Comment entity, his Post parent entity is loaded as the default mode for @ManyToOne, which is EAGER. We can also choose to not load the Post entity by changing this annotation to LAZY:

@ManyToOne(fetch = FetchType.LAZY) 
@JoinColumn(name = "post_id") 
private Post post;

Note that as the LAZY is not a requirement, the persistence provider can still load the Post entity eagerly if it wants. So for using this strategy properly, we should go back to the official documentation of the corresponding persistence provider.

Now, because we’ve used annotations to describe our fetching strategy, our definition is static and there is no way to switch between the LAZY and EAGER at runtime.

This is where the Entity Graph come into play as we’ll see in the next section.

5. Defining an Entity Graph

To define an Entity Graph, we can either use the annotations on the entity or we can proceed programmatically using the JPA API.

5.1. Defining an Entity Graph with Annotations

The @NamedEntityGraph annotation allows specifying the attributes to include when we want to load the entity and the related associations.

So let’s first define an Entity Graph that loads the Post and his related entities User and Comments:

@NamedEntityGraph(
  name = "post-entity-graph",
  attributeNodes = {
    @NamedAttributeNode("subject"),
    @NamedAttributeNode("user"),
    @NamedAttributeNode("comments"),
  }
)
@Entity
public class Post {

    @OneToMany(mappedBy = "post")
    private List<Comment> comments = new ArrayList<>();
    
    //...
}

In this example, we’ve used the @NamedAttributeNode to define the related entities to be loaded when the root entity is loaded.

Let’s now define a more complicated Entity Graph where we want also load the Users related to the Comments.

For this purpose, we’ll use the @NamedAttributeNode subgraph attribute. This allows referencing a named subgraph defined through the @NamedSubgraph annotation:

@NamedEntityGraph(
  name = "post-entity-graph-with-comment-users",
  attributeNodes = {
    @NamedAttributeNode("subject"),
    @NamedAttributeNode("user"),
    @NamedAttributeNode(value = "comments", subgraph = "comments-subgraph"),
  },
  subgraphs = {
    @NamedSubgraph(
      name = "comments-subgraph",
      attributeNodes = {
        @NamedAttributeNode("user")
      }
    )
  }
)
@Entity
public class Post {

    @OneToMany(mappedBy = "post")
    private List<Comment> comments = new ArrayList<>();
    //...
}

The definition of the @NamedSubgraph annotation is similar to the @NamedEntityGraph and allows to specify attributes of the related association. Doing so, we can construct a complete graph.

In the example above, with the defined ‘post-entity-graph-with-comment-users’  graph, we can load the Post, the related User, the Comments and the Users related to the Comments.

Finally, note that we can alternatively add the definition of the Entity Graph using the orm.xml deployment descriptor:

<entity-mappings>
  <entity class="com.baeldung.jpa.entitygraph.Post" name="Post">
    ...
    <named-entity-graph name="post-entity-graph">
            <named-attribute-node name="comments" />
    </named-entity-graph>
  </entity>
  ...
</entity-mappings>

5.2. Defining an Entity Graph with the JPA API

We can also define the Entity Graph through the EntityManager API by calling the createEntityGraph() method:

EntityGraph<Post> entityGraph = entityManager.createEntityGraph(Post.class);

To specify the attributes of the root entity, we use the addAttributeNodes() method.

entityGraph.addAttributeNodes("subject");
entityGraph.addAttributeNodes("user");

Similarly, to include the attributes from the related entity, we use the addSubgraph() to construct an embedded Entity Graph and then we the addAttributeNodes() as we did above.

entityGraph.addSubgraph("comments")
  .addAttributeNodes("user");

Now that we have seen how to create the Entity Graph, we’ll explore how to use it in the next section.

6. Using the Entity Graph

6.1. Types of Entity Graphs

JPA defines two properties or hints by which the persistence provider can choose in order to load or fetch the Entity Graph at runtime:

  • jakarta.persistence.fetchgraph – Only the specified attributes are retrieved from the database. As we are using Hibernate in this tutorial, we can note that in contrast to the JPA specs, attributes statically configured as EAGER are also loaded.
  • jakarta.persistence.loadgraph – In addition to the specified attributes, attributes statically configured as EAGER are also retrieved.

In either case, the primary key and the version if any are always loaded.

6.2. Loading an Entity Graph

We can retrieve the Entity Graph using various ways.

Let’s start by using the EntityManager.find() method. As we’ve already shown, the default mode is based on the static meta-strategies FetchType.EAGER and FetchType.LAZY.

So let’s invoke the find() method and inspect the log:

Post post = entityManager.find(Post.class, 1L);

Here is the log provided by Hibernate implementation:

select
    post0_.id as id1_1_0_,
    post0_.subject as subject2_1_0_,
    post0_.user_id as user_id3_1_0_ 
from
    Post post0_ 
where
    post0_.id=?

As we can see from the log, the User and Comment entities are not loaded.

We can override this default behavior by invoking the overloaded find() method which accepts hints as a Map. We can then provide the graph type which we want to load:

EntityGraph entityGraph = entityManager.getEntityGraph("post-entity-graph");
Map<String, Object> properties = new HashMap<>();
properties.put("jakarta.persistence.fetchgraph", entityGraph);
Post post = entityManager.find(Post.class, id, properties);

If we look again in the log, we can see that these entities are now loaded and only in one select query:

select
    post0_.id as id1_1_0_,
    post0_.subject as subject2_1_0_,
    post0_.user_id as user_id3_1_0_,
    comments1_.post_id as post_id3_0_1_,
    comments1_.id as id1_0_1_,
    comments1_.id as id1_0_2_,
    comments1_.post_id as post_id3_0_2_,
    comments1_.reply as reply2_0_2_,
    comments1_.user_id as user_id4_0_2_,
    user2_.id as id1_2_3_,
    user2_.email as email2_2_3_,
    user2_.name as name3_2_3_ 
from
    Post post0_ 
left outer join
    Comment comments1_ 
        on post0_.id=comments1_.post_id 
left outer join
    User user2_ 
        on post0_.user_id=user2_.id 
where
    post0_.id=?

Let’s see how we can achieve the same thing using JPQL:

EntityGraph entityGraph = entityManager.getEntityGraph("post-entity-graph-with-comment-users");
Post post = entityManager.createQuery("select p from Post p where p.id = :id", Post.class)
  .setParameter("id", id)
  .setHint("jakarta.persistence.fetchgraph", entityGraph)
  .getSingleResult();

And finally, let’s have a look at a Criteria API example:

EntityGraph entityGraph = entityManager.getEntityGraph("post-entity-graph-with-comment-users");
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Post> criteriaQuery = criteriaBuilder.createQuery(Post.class);
Root<Post> root = criteriaQuery.from(Post.class);
criteriaQuery.where(criteriaBuilder.equal(root.<Long>get("id"), id));
TypedQuery<Post> typedQuery = entityManager.createQuery(criteriaQuery);
typedQuery.setHint("jakarta.persistence.loadgraph", entityGraph);
Post post = typedQuery.getSingleResult();

In each of these, the graph type is given as a hint. While in the first example, we used the Map, in the two later examples we’ve used the setHint() method.

7. Conclusion

In this article, we’ve explored using the JPA Entity Graph to dynamically fetch an Entity and its associations.

The decision is made at runtime in which we choose to load or not the related association.

Performance is obviously a key factor to take into account when designing JPA entities. The JPA documentation recommends using the FetchType.LAZY strategy whenever possible, and the Entity Graph when we need to load an association.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

Course – LSD – NPI (cat=JPA)
announcement - icon

Get started with Spring Data JPA through the reference Learn Spring Data JPA:

>> CHECK OUT THE COURSE

eBook Jackson – NPI EA – 3 (cat = Jackson)