views:

491

answers:

3

consider this scenario:

  • I have loaded a Parent entity through hibernate
  • Parent contains a collection of Children which is large and lazy loaded
  • The hibernate session is closed after this initial load while the user views the Parent data
  • The user may choose to view the contents of the lazy Children collection
  • I now wish to load that collection

What are the ways / best way of loading this collection?

  • Assume session-in-view is not an option as the fetching of the Children collection would only happen after the user has viewed the Parent and decided to view the Children.
  • This is a service which will be accessed remotely by web and desktop based client.

Thanks.

+2  A: 

I'm making some assumptions about what the user is looking at, but it seems like you only want to retrieve the children if the user has already viewed the parent and really wants to see the children.

Why not try opening a new session and fetching the children by their parent? Something along the lines of ...

criteria = session.createCriteria(Child.class);
criteria.add(Restrictions.eq("parent", parent));
List<Child> children = criteria.list();
zmf
nice one. i missed that you could specify objects in a Restriction.
+3  A: 

The lazy collection can be loaded by using Hibernate.initialize(parent.getCollection()) except that the parent object needs to be attached to an active session.

This solution takes the parent Entity and the name of the lazy-loaded field and returns the Entity with the collection fully loaded.

Unfortunately, as the parent needs to be reattached to the newly opened session, I can't use a reference to the lazy collection as this would reference the detached version of the Entity; hence the fieldName and the reflection. For the same reason, this has to return the attached parent Entity.

So in the OP scenario, this call can be made when the user chooses to view the lazy collection:

Parent parentWithChildren = dao.initialize(parent,"lazyCollectionName");

The Method:

public Entity initialize(Entity detachedParent,String fieldName) {
    // ...open a hibernate session...
    // reattaches parent to session
    Entity reattachedParent = (Entity) session.merge(detachedParent); 

    // get the field from the entity and initialize it
    Field fieldToInitialize = detachedParent.getClass().getDeclaredField(fieldName);
    fieldToInitialize.setAccessible(true);
    Object objectToInitialize = fieldToInitialize.get(reattachedParent);

    Hibernate.initialize(objectToInitialize);
    return reattachedParent;
}
A: 

Hibernate handles collections in a different way that normal fields.

At my work we get around this by just initialising the fields in the initial load that we need on a case by case basis. For example, in a facade load method that is surrounded by a transaction you might have:

public Parent loadParentWithIntent1(Long parentId)
{
  Parent parent = loadParentFromDAO();

  for (Child c : parent.getChildren())
  {
    c.getField1();
  }
}

and we have a different facade call for each intent. This essentially achieves what you need because you'd be loading these specific fields when you need them any way and this just puts them in the session at load time.

bwobbones
I take it the down-side of this approach is n+1 queries.