Home » Java » Enterprise Java » JPA 2.1 Entity Graph – Part 2: Define lazy/eager loading at runtime

About Thorben Janssen

Thorben Janssen is a senior developer with more than 10 years of experience in Java EE development and architecture. During these years he acted as developer, architect, project and/or technical lead to create high available, clustered mobile billing solutions and laboratory information management systems.

JPA 2.1 Entity Graph – Part 2: Define lazy/eager loading at runtime

This is my second post on JPA 2.1 Entity Graphs. The first post described the usage of named entity graphs. These can be used to define a graph of entities and/or attributes at compile time that shall be fetched with a find or query method. Dynamic entity graphs do to the same but in a dynamic way. This means you can use the EntityGraph API to define your entity graph at runtime.

If you have missed the first post and want to read how to define a named entity graph or how lazy loading issues were solved with JPA 2.0, check this post: JPA 2.1 Entity Graph – Part 1: Named entity graphs.

The example entities

We will use the same example as in the previous post. So you can skip this paragraph if you have read the other one.

We will use 3 entities. These are Order, OrderItem and Product. An Order might include multiple OrderItems and each OrderItem belongs to one Product. The FetchType of all these relations it FetchType.LAZY. So the entity manager will not fetch them from the database by default and initialize them with a proxy instead.

The Order entity:

@Entity
@Table(name = "purchaseOrder")
@NamedEntityGraph(name = "graph.Order.items", 
               attributeNodes = @NamedAttributeNode(value = "items", subgraph = "items"), 
               subgraphs = @NamedSubgraph(name = "items", attributeNodes = @NamedAttributeNode("product")))
public class Order implements Serializable {

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   @Column(name = "id", updatable = false, nullable = false)
   private Long id = null;
   @Version
   @Column(name = "version")
   private int version = 0;

   @Column
   private String orderNumber;

   @OneToMany(mappedBy = "order", fetch = FetchType.LAZY)
   private Set<OrderItem> items = new HashSet<OrderItem>();

   ...

The OrderItem entity:

@Entity
public class OrderItem implements Serializable
{

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   @Column(name = "id", updatable = false, nullable = false)
   private Long id = null;
   @Version
   @Column(name = "version")
   private int version = 0;

   @Column
   private int quantity;

   @ManyToOne
   private Order order;

   @ManyToOne(fetch = FetchType.LAZY)
   private Product product;

The Product entity:

@Entity
public class Product implements Serializable
{

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   @Column(name = "id", updatable = false, nullable = false)
   private Long id = null;
   @Version
   @Column(name = "version")
   private int version = 0;

   @Column
   private String name;

Dynamic entity graph

So let’s define a dynamic entity graph. We will do the same as in the first post and define a simple entity graph that tells the entity manager to fetch an Order with all associated OrderItems. Therefore we use the createEntityGraph(ClassrootType) method of the entity manager to create an entity graph for the Order entity. In the next step, we create a list of all attributes of the Order entity that shall be fetched with this entity graph. We only need to add the attribute items, because we will use this entity graph as a loadgraph and all other attributes are eager by default.

If we would use this entity graph as a fetchgraph, we would need to add all attributes to the list that should be fetched from the database.

EntityGraph<Order> graph = this.em.createEntityGraph(Order.class);
graph.addAttributeNodes("items");

Map<String, Object> hints = new HashMap<String, Object>();
hints.put("javax.persistence.loadgraph", graph);

this.em.find(Order.class, orderId, hints);

OK, dynamically defining which attributes of an entity shall be fetched from the database is nice. But what if we need a graph of entities? Like fetching an Order with all its OrderItems and their Product?

This can be done with a sub graph. A sub graph is basically an entity graph that is embedded into another entity graph or entity sub graph. The definition of a sub graph is similar to the definition of an entity graph. To create and embed the sub graph into an entity graph, we need to call the addSubgraph(String attributeName) method on an EntityGraph object. This will create a sub graph for the attribute with the given name. In the next step, we need to define the list of attributes that shall be fetched with this sub graph.

The following snippet shows the definition of an entity graph with an entity sub graph which tell the entity manager to fetch an Order with its OrderItems and their Product.

EntityGraph<Order> graph = this.em.createEntityGraph(Order.class);
Subgraph<OrderItem> itemGraph = graph.addSubgraph("items");
itemGraph.addAttributeNodes("product");

Map<String, Object> hints = new HashMap<String, Object>();
hints.put("javax.persistence.loadgraph", graph);

return this.em.find(Order.class, orderId, hints);

What’s happening inside?

As in the previous post, we want to have a look at the hibernate log and find out what hibernate is doing. As we can see, the result of a dynamic entity graph is the same as of a named entity graph. It creates a load plan and one select statement with all 3 entities.

2014-04-07 20:08:15,260 DEBUG [org.hibernate.loader.plan.build.spi.LoadPlanTreePrinter] (default task-2) LoadPlan(entity=blog.thoughts.on.java.jpa21.entity.graph.model.Order)
    - Returns
       - EntityReturnImpl(entity=blog.thoughts.on.java.jpa21.entity.graph.model.Order, querySpaceUid=, path=blog.thoughts.on.java.jpa21.entity.graph.model.Order)
          - CollectionAttributeFetchImpl(collection=blog.thoughts.on.java.jpa21.entity.graph.model.Order.items, querySpaceUid=, path=blog.thoughts.on.java.jpa21.entity.graph.model.Order.items)
             - (collection element) CollectionFetchableElementEntityGraph(entity=blog.thoughts.on.java.jpa21.entity.graph.model.OrderItem, querySpaceUid=, path=blog.thoughts.on.java.jpa21.entity.graph.model.Order.items.)
    - QuerySpaces
       - EntityQuerySpaceImpl(uid=, entity=blog.thoughts.on.java.jpa21.entity.graph.model.Order)
          - SQL table alias mapping - order0_
          - alias suffix - 0_
          - suffixed key columns - {id1_2_0_}
          - JOIN (JoinDefinedByMetadata(items)) :  -> 
             - CollectionQuerySpaceImpl(uid=, collection=blog.thoughts.on.java.jpa21.entity.graph.model.Order.items)
                - SQL table alias mapping - items1_
                - alias suffix - 1_
                - suffixed key columns - {order_id4_2_1_}
                - entity-element alias suffix - 2_
                - 2_entity-element suffixed key columns - id1_0_2_
                - JOIN (JoinDefinedByMetadata(elements)) :  -> 
                   - EntityQuerySpaceImpl(uid=, entity=blog.thoughts.on.java.jpa21.entity.graph.model.OrderItem)
                      - SQL table alias mapping - items1_
                      - alias suffix - 2_
                      - suffixed key columns - {id1_0_2_}

2014-04-07 20:08:15,260 DEBUG [org.hibernate.loader.entity.plan.EntityLoader] (default task-2) Static select for entity blog.thoughts.on.java.jpa21.entity.graph.model.Order [NONE:-1]: select order0_.id as id1_2_0_, order0_.orderNumber as orderNum2_2_0_, order0_.version as version3_2_0_, items1_.order_id as order_id4_2_1_, items1_.id as id1_0_1_, items1_.id as id1_0_2_, items1_.order_id as order_id4_0_2_, items1_.product_id as product_5_0_2_, items1_.quantity as quantity2_0_2_, items1_.version as version3_0_2_ from purchaseOrder order0_ left outer join OrderItem items1_ on order0_.id=items1_.order_id where order0_.id=?

Conclusion

After defining a named entity graph in the first post, we now used the EntityGraph API to define an dynamic entity graph. Using this entity graph, we can fetch a graph of multiple entities with only one query from the database. This can be used to solve LazyInitializationException and to improve the performance applications.

What do you think about (dynamic) entity graphs? From my point of view this is a very useful extension compared to JPA 2.0. Especially the dynamic entity graphs are useful to define your fetch strategy based on runtime information like method parameters.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design

and many more ....

 

3 comments

  1. Very interssent feature.

    In two words. there are two way to get a relation object :
    – In persistence layer : create a specific query to load the entity and the related object relation. this solution isn’t generic. in other words for every object relation we have to create a specific request to load entity and the object relation together.

    – In business layer : in this case the object relation is loaded when it is accessed for the first time. the disadvantage of this solution is the nombre of query generated (one query by object).

    Graph entity allows to load dynamicly the relation. it is query independent and results in only one select statement.

  2. Hi Sidi,

    thanks for your comment.

    You are right, these were the two options we had with JPA 2.0. I did not discuss these options in this post, because I already did that in the first part of the series: http://www.thoughts-on-java.org/2014/03/jpa-21-entity-graph-part-1-named-entity.html
    You might also want to check that one, if you want to read more about named entity graphs. The idea is basically the same, but you define the entity graph with an annotation at development time.

    Regards,
    Thorben

  3. This is very interesting. For those C# developers with some Entity Framework background that are now (forced?) to work in the JPA world, this capability of defining an EntityGraph gives the same capability that LINQ querries using .Include() clauses in their Entity Framework expression:

    using (OrderEntities oContext = new OrderEntities())
    {
    Order o = oContext.Orders.Include(o => o.items).FirstOrDefault(o=>o.orderId == someOrderId);
    }

    to include products under that you would:
    oContext.Include(o=>o.items.select(oi=>oi.Product).FirstOrDefault(o=>o.orderId == someOrderId);

    I do like the way the graph applies the fetch strategy externally from embedding it in the LINQ expression as we see here in the C# context. But in case anyone wondered how to do the equivalent of Include() from C# in JPA, here it is!

Leave a Reply

Your email address will not be published. Required fields are marked *

*


two + = 11

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Want to take your Java Skills to the next level?
Grab our programming books for FREE!
  • Save time by leveraging our field-tested solutions to common problems.
  • The books cover a wide range of topics, from JPA and JUnit, to JMeter and Android.
  • Each book comes as a standalone guide (with source code provided), so that you use it as reference.
Last Step ...

Where should we send the free eBooks?

Good Work!
To download the books, please verify your email address by following the instructions found on the email we just sent you.