2010-11-29 8 views
39

Tengo un servicio que obtiene una entidad JPA desde un código externo. En este servicio me gustaría iterar sobre una colección cargada de forma diferida que es un atributo de esta entidad para ver si el cliente le ha agregado algo en relación con la versión actual en la base de datos.¿Cómo se prueba si la colección de JPA con carga diferida está inicializada?

Sin embargo, es posible que el cliente nunca haya tocado la colección, por lo que aún no se ha inicializado. Esto da lugar a la conocida

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

Por supuesto, si el cliente nunca tocó la colección, mi servicio no tiene que comprobar que los posibles cambios. La cuestión es que parece que no puedo encontrar una forma de comprobar si la colección está inicializada o no. Supongo que podría llamar al size() y si arroja LazyInitializationException lo sabría, pero estoy tratando de no depender de esos patrones.

¿Hay algún método de isInitialized() en alguna parte?

Respuesta

48

¿Estás utilizando JPA2?

PersistenceUnitUtil tiene dos métodos que se pueden utilizar para determinar el estado de carga de una entidad.

p. Ej. hay una relación OneToMany/ManyToOne bidireccional entre Organización y Usuario.

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(); 
} 
+1

¡Tiene razón, gracias! Olvidé revisar el desbordamiento de pila, así que lamento la aceptación tardía. – akira

20
org.hibernate.Hibernate.isInitialized(..) 

No tengo una solución JPA estándar que yo sepa. Pero si realmente quiere inicializar colecciones, puede crear un método de utilidad e iterarlas (solo una iteración es suficiente).

+1

Eso es exactamente lo que estoy buscando, ¡gracias! El problema es que aunque estoy usando Hibernate, el código debe ser compatible con JPA, así que desafortunadamente no puedo usar esto :( – akira

+1

no hay nada estándar. – Bozho

+0

entityManager.find() es bastante estándar;) Poner de manera diferente, el código también debería funcionar en EclipseLink;) – akira

2

Como indica el otro cartel, Hibernate tiene un método para esto. Sin embargo, no hay una solución para esto en JPA puro.

Cuestiones relacionadas