Java Persistence with Hibernate shows lots of examples of how to eagerly fetch associated entities, such as:
- Adding @org.hibernate.annotations.BatchSize to the associated class
- Adding @org.hibernate.annotations.Fetch to the field that references the associated class
- Using the "fetch" keyword in the HQL query, etc...
However in my case, I am dealing with a slow-running process that is responsible for building associations to the entity class of interest. That means that - at the time of execution - I can't query one entity and ask it to eagerly fetch all the associated instances of the other entity since no such association exists.
In other words, the process looks something like this:
public class InitConfig {
private final SessionFactory sessionFactory;
private final NodeManager nodeManager;
public void run() {
final Configuration config = new Configuration("NewConfiguration", new HashSet<Node> ());
for(String name : lotsOfNames) {
//Lots of these queries run slowly
final Node node = this.nodeManager.getNode(name);
config.addNode(node);
}
this.sessionFactory.getCurrentSession().save(config);
}
}
The related DAO (NodeManager) and slow-querying Entity (Node) look like this:
public class NodeManager {
private final SessionFactory sessionFactory;
public Node getNode(String name) {
final Session db = this.sessionFactory.getCurrentSession();
final Query query = db.createQuery("from NODE where NAME = :name");
query.setString("name", name);
return (Node)query.uniqueResult();
}
}
@Entity(name="NODE")
public class Node {
@GeneratedValue(strategy=GenerationType.TABLE)
@Id @Column(name="ID")
private Long id;
private @Column(name="NAME", nullable=false, unique=true) String name;
//Other properties and associations...
}
And finally, the entity being created by the slow-running process:
@Entity(name="CONFIGURATION")
public class Configuration {
@Id @GeneratedValue @Column(name="ID")
private Long id;
private @Column(name="NAME", nullable=false, unique=true) String name;
@ManyToMany
@JoinTable(
name="CONFIGURATION_NODE",
joinColumns=@JoinColumn(name="CONFIGURATION_ID", nullable=false),
inverseJoinColumns=@JoinColumn(name="NODE_ID", nullable=false))
private Set<Node> nodes = new HashSet<Node> ();
public void addNode(Node node) {
this.nodes.add(node);
}
}
My question is this: How do I modify the Hibernate configuration and/or code to eagerly fetch many instances of Node at a time?
Follow on questions would be:
- Is Hibernate's 2nd level cache appropriate for this, and if so - how do I configure it?
- If not, is there some other Hibernate feature that can be used here?
There are roughly 100,000 Nodes at the moment, so I'm reluctant to take the brute-force approach of querying every single Node and caching it in the application somewhere, since that would not scale to higher numbers of Nodes and seems like it would duplicate data between the application and Hibernate's internals (Session, 2nd level cache, etc...).