0

I have a directory type structure represented as entities, i.e. think Directory entity and File entity.

The Directory entity has a collection of File entities and a collection of Directory entities.

I want to get the root directory and 'pre load' all directories and there files.

I am trying:

String queryString = "SELECT DISTINCT d FROM " + 
   Directory.class.getSimpleName() + 
   " d LEFT JOIN FETCH d.files LEFT JOIN FETCH d.directories child LEFT JOIN FETCH child.files LEFT JOIN FETCH child.directories WHERE f.root = :isRoot);
Query query = em.createQuery(queryString);
query.setParameter("isRoot", true);

Directory dir = (Directory) query.getSingleResult();

The query works it just does not pre load everything. I get all of the root directories and the root files, but when I start going into the sub directories and get the files queries are made. I.E. it seems like the recursion is not working.

I have also tried just a JOIN FETCH (which I think does an inner join fetch) with no luck.

Any ideas?

lostintranslation
  • 23,756
  • 50
  • 159
  • 262
  • It sure does! If you read the documentation is states:A fetch join does not usually need to assign an alias, because the associated objects should not be used in the where clause (or any other clause). The associated objects are also not returned directly in the query results. Instead, they may be accessed via the parent object. The only reason you might need an alias is if you are recursively join fetching a further collection: from Cat as cat inner join fetch cat.mate left join fetch cat.kittens child left join fetch child.kittens – lostintranslation Mar 20 '12 at 19:01
  • So if you read furthur in that post this is what I am looking for: 'While it isn't possible to write the recursive query you're asking for, it is possible to eager fetch the hierarchy with HQL; doing this would at least allow you to walk the tree in memory without hitting the database for each level. select n from Node n left join fetch n.Children' – lostintranslation Mar 20 '12 at 19:04

2 Answers2

2

I faced the same issue but in my case a single table stored multiple independent trees. So that "select n from Node n left join fetch n.Children" would've fetched all trees into memory while I needed the single one. Adding a WHERE clause would've broken the recursion.

So I used a recursion helper inside my DAO:

private Node fetchChildren(Node parent) {
    Hibernate.initialize(parent.getChildren());
    for (Node child : parent.getChildren()) {
        fetchChildren(child);
    }
    return parent;
} 
Vlad
  • 736
  • 1
  • 7
  • 11
0

Have you defined the fetch between the entities as eager (@OneToMany(fetch=FetchType.EAGER))?

It seems it could solve the initial fetching issue for your problem (more detailed answer).

esaj comment link answer contains the way to deal with the recursion.

Hope this helps

Community
  • 1
  • 1
Aba Dov
  • 962
  • 4
  • 12
  • 20
  • 1
    Thanks, but that is not what I want. The reason is I want to default behavior to be lazy, and only a query overriding that behavior should eagerly fetch recursively. Hibernate docs say they support this type of behavior. – lostintranslation Mar 20 '12 at 18:59