Close

Using Entity Subgraph with @NamedSubgraph

[Last Updated: Feb 21, 2018]

What are Entity Subgraphs?

In JPA, a sub entity graph is used to define "fetch plan" for an entity involving relationship to this entity. Subgraphs are defined by using @NamedSubgraph annotation. This annotation is used within the main @NamedEntityGraph annotation (last tutorial) via the attribute of 'subgraphs' . The reference of a subgraph (by using its name) is used by the 'subgraph' attribute of @NamedSubgraph. Let's understand that by an example.

Example

First we are not going to use @NamedEntityGraph on our entity:

@Entity
@NamedEntityGraph(name = "graph.module.projects.contractors",
      attributeNodes = @NamedAttributeNode(value = "projects", subgraph = "projects.contractors"),
      subgraphs = @NamedSubgraph(name = "projects.contractors",
              attributeNodes = @NamedAttributeNode(value = "contractors")))
public class TradingModule {
  @Id
  @GeneratedValue
  private int id;
  private String name;
  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
  private Set<Project> projects;
    .............
}
@Entity
public class Project {
  @Id
  @GeneratedValue
  private int id;
  private String name;
  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
  private Set<Contractor> contractors;
    .............
}
@Entity
public class Contractor {
  @Id
  @GeneratedValue
  private long id;
  private String name;
  private String role;

  public Contractor() {
  }

  public Contractor(String name, String role) {
      this.name = name;
      this.role = role;
  }
    .............
}

Using find() without an Entity Graph

public class ExampleMain {
  private static EntityManagerFactory entityManagerFactory =
          Persistence.createEntityManagerFactory("example-unit");

  public static void main(String[] args) {
      try {
          persistEntity();
          findEntity();
      } finally {
          entityManagerFactory.close();
      }
  }

  public static void persistEntity() {
      TradingModule module = getTradingModule();
      EntityManager em = entityManagerFactory.createEntityManager();
      em.getTransaction().begin();
      em.persist(module);
      em.getTransaction().commit();
      em.close();
  }

  private static void findEntity() {
      EntityManager em = entityManagerFactory.createEntityManager();
      Map<String, Object> properties = new HashMap<>();
      TradingModule module = em.find(TradingModule.class, 1, properties);
      em.close();
      printInitializeState(module);
  }

  private static void printInitializeState(TradingModule module) {
      PersistenceUtil pu = entityManagerFactory.getPersistenceUnitUtil();
      printState("TradingModule", pu.isLoaded(module));
      printState("TradingModule.name", pu.isLoaded(module, "name"));
      printState("TradingModule.projects", pu.isLoaded(module, "projects"));
      if (pu.isLoaded(module, "projects")) {
          for (Project project : module.getProjects()) {
              printState("Project", pu.isLoaded(project));
              printState("Project.name", pu.isLoaded(module, "project.name"));
              printState("Projects.contractors", pu.isLoaded(module, "project.contractors"));
          }
      }
  }

  private static void printState(String msg, boolean loaded) {
      System.out.printf("%25s loaded: %s%n", msg, loaded);
  }

  public static TradingModule getTradingModule() {
      Project project = new Project();
      project.setName("Price/Yield Calculator");
      project.addContractor(new Contractor("Margaret", "Project Manager"));
      project.addContractor(new Contractor("Steven", "Developer"));
      project.addContractor(new Contractor("Claudie", "Business Analyst"));

      TradingModule module = new TradingModule();
      module.setName("Fixed Income");
      module.addProject(project);
      return module;
  }
}
            TradingModule loaded: true
TradingModule.name loaded: true
TradingModule.projects loaded: false

Using Entity Graph with javax.persistence.fetchgraph

public class ExampleMain2 {
  private static EntityManagerFactory entityManagerFactory =
          Persistence.createEntityManagerFactory("example-unit");
    .............
  private static void findEntity() {
      EntityManager em = entityManagerFactory.createEntityManager();
      EntityGraph graph = em.getEntityGraph("graph.module.projects.contractors");
      Map<String, Object> properties = new HashMap<>();
      properties.put("javax.persistence.fetchgraph", graph);
      TradingModule module = em.find(TradingModule.class, 1, properties);
      em.close();
      printInitializeState(module);
  }
    .............
}
            TradingModule loaded: true
TradingModule.name loaded: true
TradingModule.projects loaded: true
Project loaded: true
Project.name loaded: true
Projects.contractors loaded: true

Check out the last tutorial, to understand 'fetchgraph' semantics defined by JPA specification and why Hibernate ignores some of the rules.

Example Project

Dependencies and Technologies Used:

  • h2 1.4.196: H2 Database Engine.
  • hibernate-core 5.2.12.Final: The core O/RM functionality as provided by Hibernate.
    Implements javax.persistence:javax.persistence-api version 2.1
  • JDK 1.8
  • Maven 3.3.9

Entity Subgraph Example Select All Download
  • jpa-entity-sub-graph-example
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • TradingModule.java
          • resources
            • META-INF

    See Also