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