53

I have a service that gets a JPA entity from outside code. In this service I would like to iterate over a lazily loaded collection that is an attribute of this entity to see if the client has added something to it relative to the current version in the DB.

However, the client may have never touched the collection so it's still not initialized. This results in the well known

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.SomeEntity.

Of course, if the client never touched the collection, my service doesn't have to check it for possible changes. The thing is that I can't seem to find a way to test whether the collection is initialized or not. I guess I could call size() on it and if it throws LazyInitializationException I would know, but I'm trying not to depend on such patterns.

Is there some isInitialized() method somewhere?

Andremoniy
  • 31,241
  • 14
  • 110
  • 218
akira
  • 1,721
  • 2
  • 16
  • 17

3 Answers3

61

Are you using JPA2?

PersistenceUnitUtil has two methods that can be used to determine the load state of an entity.

e.g. there is a bidirectional OneToMany/ManyToOne relationship between Organization and User.

public void test() {
    EntityManager em = entityManagerFactory.createEntityManager();
    PersistenceUnitUtil unitUtil =
        em.getEntityManagerFactory().getPersistenceUnitUtil();

    em.getTransaction().begin();
    Organization org = em.find(Organization.class, 1);
    em.getTransaction().commit();

    Assert.assertTrue(unitUtil.isLoaded(org));
    // users is a field (Set of User) defined in Organization entity
    Assert.assertFalse(unitUtil.isLoaded(org, "users"));

    initializeCollection(org.getUsers());
    Assert.assertTrue(unitUtil.isLoaded(org, "users"));
    for(User user : org.getUsers()) {
        Assert.assertTrue(unitUtil.isLoaded(user));
        Assert.assertTrue(unitUtil.isLoaded(user.getOrganization()));
    }
}

private void initializeCollection(Collection<?> collection) {
    // works with Hibernate EM 3.6.1-SNAPSHOT
    if(collection == null) {
        return;
    }
    collection.iterator().hasNext();
}
Nicolai Parlog
  • 36,673
  • 16
  • 109
  • 236
dira
  • 28,648
  • 13
  • 50
  • 69
  • 1
    You are right, thanks! I forgot to check back at stack overflow, so sorry for the late acceptance. – akira Jan 04 '11 at 12:15
29
org.hibernate.Hibernate.isInitialized(..)

There is no standard JPA solution to my knowledge. But if you want to actually initialize collections, you can create an utility method and iterate them (only one iteration is enough).

Bozho
  • 554,002
  • 136
  • 1,025
  • 1,121
  • 1
    That's exactly what I'm looking for, thanks! The problem is that even though I happen to be using Hibernate, the code should be JPA compliant so unfortunately I'm not really able to use this :( – akira Dec 01 '10 at 10:36
  • entityManager.find() is pretty standard ;) Put differently, the code should also work on EclipseLink ;) – akira Dec 01 '10 at 12:43
  • isn't find() doing a different thing? – Bozho Dec 01 '10 at 12:44
  • Yes, but I meant that you said "nothing is standard", but find, even though it does something else, works on both Hibernate and EclipseLink. So in other words "standards do exists". – akira Mar 23 '11 at 16:56
  • This works for me as well. Though I find the Hibernate abstraction very leaky. I don't want to have in my controllers code like 'Hibernate.xy()'. I see why cannot it be easily fixed since Hibernate traded a lot for the promise to work 'seamlessly' which then results in such abstraction leaks... – Ondrej Burkert Jul 27 '16 at 13:15
  • _"But if you want to actually initialize collections, you can create an utility method and iterate them"_ This is false at least with Hibernate. Actually if you do that on a detached initialized collection you will get `LazyInitializationException: failed to lazily initialize a collection`. Explanation: A lazy initialized collection is not a List or a Set but an Hibernate PersistentCollection, or PersistentBag. That thing has to have the session associated to, and be referenced in the persistent context, or else the initialisation won't be performed – Aldian Nov 03 '16 at 14:37
2

For eclipselink, users cast the collection you are trying to access to an org.eclipse.persistence.indirection.IndirectList, and then call its isInstantiated() method. The following link has more information:

http://www.eclipse.org/eclipselink/api/1.1/org/eclipse/persistence/indirection/IndirectList.html#isInstantiated.

Boeckm
  • 3,085
  • 4
  • 34
  • 41
amax
  • 29
  • 1