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 ProjectDependencies 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
|