Pregunta

Tengo un problema con Hibernate y el LazyInitializationException. Busqué y encontré muchas respuestas, pero no puedo usarlos para resolver mi problema, porque tengo que decir, soy nuevo en hibernación.

corro pruebas JUnit, en el caso del error de ésta:

@Test
public void testAddPerson() {
    Set<Person> persons = service.getAllPersons();

    // create new person
    Person person = new Person();
    person.setEmail("john@doe.com");
    Project testProject = serviceProj.findProjectById(1);

    HashSet<Project> lister = new HashSet<Project>();
    lister.add(testProject);
    person.setProjects(lister);
    service.addPerson(person);

    testProject.getPersons().add(person);
    ...
}

La última línea se muestra:

testProject.getPersons().add(person);

lanza este error:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.doe.john.domain.Project.persons, no session or session was closed

Persona y Proyecto son bidireccionales n: m:

Person.java

@ManyToMany(mappedBy="persons")
private Set<Project> projects = new HashSet<Project>();

Project.java

@ManyToMany
@JoinTable(name = "Project_Person",
    joinColumns = {@JoinColumn(name="project_id", referencedColumnName="id")},
    inverseJoinColumns = {@JoinColumn(name="person_id", referencedColumnName="id")}
)
private Set<Person> persons = new HashSet<Person>();

Entonces, ¿cuál es el problema?

¿Fue útil?

Solución

El problema es que por defecto se carga con pereza la colección. Esto significa que en realidad no será cargado desde la base de datos hasta que se está accediendo. Con el fin de cargarlo necesitará una sesión / transacción activa.

El camino más fácil es cambiar a FethType.EAGER el que se asegura de que la colección se llena enseguida.

- Actualización -

Recientemente he tenido el mismo problema y que terminó modificando mi servicio real para hacer frente a este tipo de cosas. Declarar un método addPerson en su clase ProjectService.

public void addPersonTo(Project project, Person person)
{
  project = em.merge(project); //EntityManager, not sure what you are using but you get the idea hopefully
  project.addPerson(person);
}

Otros consejos

Ponga su código dentro de una transacción - esto va a resolver el problema para usted

Se puede tratar

person.getProjects().Add(testProject)

en lugar de

HashSet<Project> lister = new HashSet<Project>();
lister.add(testProject);
person.setProjects(lister);

Usted debería hacer esto ya que de lo contrario estaría Arrancar una colección logrado hibernación.

De referencia de hibernación:

Por defecto, Hibernate3 utiliza recuperación perezosa por selección para las colecciones y por proxy perezosa para asociaciones de un solo valor. Estos valores por defecto tienen sentido para la mayoría de las asociaciones en la mayoría de las aplicaciones.

Si define hibernate.default_batch_fetch_size, Hibernate usará el lote ha podido ir a la optimización de la recuperación perezosa. Esta optimización también se puede habilitar a un nivel más granular.

Por favor, tenga en cuenta que el acceso a una asociación fuera perezoso del contexto de una sesión de Hibernate abierta dará lugar a una excepción. Por ejemplo:

s = sessions.openSession();
Transaction tx = s.beginTransaction();

User u = (User) s.createQuery("from User u where u.name=:userName")
.setString("userName", userName).uniqueResult();
Map permissions = u.getPermissions();

tx.commit();
s.close();

Integer accessLevel = (Integer) permissions.get("accounts");  // Error!

Desde la colección de permisos no se ha inicializado cuando la sesión se cerró, la colección no será capaz de cargar su estado. Hibernate no soporta la inicialización perezosa de objetos separados. Esto se puede solucionar moviendo el código que se lee de la colección hasta justo antes de la transacción se confirma.

Alternativamente, se puede utilizar una colección o asociación no perezoso, especificando = perezosas "falso" para el mapeo de asociación. Sin embargo, se pretende que la inicialización perezosa puede utilizar para casi todas las colecciones y asociaciones. Si define demasiadas asociaciones no perezosos en su modelo de objetos, Hibernate recuperará toda la base de datos en la memoria en cada transacción.

Por otro lado, puede utilizar la recuperación por unión, que no es perezoso por naturaleza, en lugar de la recuperación por selección en una transacción en particular. Ahora vamos a explicar cómo personalizar la estrategia de recuperación. En Hibernate3, los mecanismos para la elección de una estrategia de recuperación son idénticas para las asociaciones de un solo valor y colecciones.

Así que hay que cerrar la sesión después de acceder a la colección!

En lugar de:

service.addPerson(person);

testProject.getPersons().add(person);

Yo creo que se debe tener:

testProject.getPersons().add(person);
service.addPerson(person);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top