Enviar respuesta 
 
Calificación:
  • 0 votos - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
Ayuda para cargar listas desde BD [Resuelto]
dgalo88 Sin conexión
lider de proyecto
****

Mensajes: 74
Registro en: Jun 2010
Reputación: 0
Mensaje: #1
Ayuda para cargar listas desde BD [Resuelto]
Hola!!!

Hace unos días tuve un problema cargando una lista desde la base de datos y el prof. Demian me ayudo, aquí coloco la conversación:

demian escribió:Hola Donato.

Esta es la clase de cosas que se dicen directo en el foro, no por MP Smile
Lo digo porque la respuesta que te de puede beneficiar a otros.

Ahora paso a responderte (con una condición, que publiques esto en la sección de BD y yo te publico mi respuesta).

dgalo88 escribió:
Código:
@OneToMany(mappedBy = "studentRef")
@LazyCollection(LazyCollectionOption.TRUE)
@Cascade({CascadeType.ALL,CascadeType.DELETE_ORPHAN})
public List<Poll> getPollList() {
    return pollList;
}

Esto me daba un error por el DELETE_ORPHAN, lo cambié por SAVE_UPDATE y aparentemente funciona.

En efecto, esto cambió a partir de cierta versión de hibernate. Es más que nada un cambio cosmético del API, la cosa ahora es:

Código:
@OneToMany(mappedBy = "unoRef", orphanRemoval = true)
@LazyCollection(LazyCollectionOption.TRUE)
@Cascade({CascadeType.ALL})

Es decir, el Cascade ALL y el DELETE_ORPHAN ahora va en el mismo @OneToMany.

dgalo88 escribió:Ahora, cuando creo las encuestas las inserto en una lista de Encuestas y luego se la asigno al estudiante, algo como lo siguiente:

Código:
Poll poll = new Poll();

...

pollList.add(poll);

student.setPollList(pollList);

Hasta aquí todo funciona bien, pero cuando intento obtener y usar esa lista es cuando aparecen los errores. Aquí el código:

Código:
pollList = student.getPollList();
...
if (pollList.isEmpty()) {
    return;
}

El error es el siguiente:

Cita:Grave: failed to lazily initialize a collection of role: com.rais.manager.database.Student.pollList, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.rais.manager.database.Student.pollList, no session or session was closed
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExc​eption(AbstractPersistentCollection.java:383)
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExc​eptionIfNotConnected(AbstractPersistentCollection.java:375)
at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersisten​tCollection.java:122)
at org.hibernate.collection.PersistentBag.isEmpty(PersistentBag.java:255)
at com.rais.manager.controller.Polls.checkPendingPoll(Polls.java:210)
...

Y la línea 210 es la condición del if
Código:
pollList.isEmpty()

No se cual es el error o que estoy haciendo mal.

Esto es el temido Lazy Exception XD. Sucede porque tienes declarado:

Código:
@LazyCollection(LazyCollectionOption.TRUE)

Eso significa que la colección es "floja" es decir, que no se carga sino hasta que alguien la usa. Cuando digo cargar me refiero a ir a la BD. De modo que tu puedes traer de la BD un objeto Poll, pero las relaciones 1:N, es decir los muchos, no se cargan sino hasta que tratas de acceder a ellas (por ejemplo, el isEmpty de la lista que es el que te da el error en este caso).

Eso es bueno, eso es un comportamiento deseable, lo podrías resolver poniendo FALSE a la opción LazyCollection (si quieres prueba), pero esa es la solución "mala" desde mi punto de vista, yo uso LazyCollection TRUE siempre por regla general, a menos que tenga una muy buena razón para no hacerlo.

¿Cómo se resuelve el problema de la forma elegante? Así:

Resulta que cuando tratas de acceder a la lista (Ej. isEmpty), la sesión a la que está asociado el objeto DEBE ESTAR ACTIVA (y creo que la transacción abierta, aunque de memoria me puedo equivocar aquí). Me explico:

Código:
Session session = sessionFactory.openSession(); // Ojo, escribo de memoria, pero mas o menos

// Hacer algo, obtener una instancia de student que viene de la BD

List<Poll> pollList = student.getPollList();

if (pollList.isEmpty()) {
  // Bla bla
}

session.close();

Mientras trates de acceder a la lista dentro de un sessionFactory.openSession() y un session.close(), no vas a tener problema. El problema lo tienes si:

Código:
Session session = sessionFactory.openSession(); // Ojo, escribo de memoria, pero mas o menos

// Hacer algo, obtener una instancia de student que viene de la BD

List<Poll> pollList = student.getPollList();

session.close();

// Aquí esto da un lazy exception, porque hibernate va a tratar de cargar la
// data de la BD... pero la session está cerrada!!!
if (pollList.isEmpty()) {
  // Bla bla
}

Eso es básicamente todo. Escribí esto muy rápido, si algo no está claro me preguntas.

Saludos,
Demian

demian escribió:
Código:
Session session = sessionFactory.openSession(); // Ojo, escribo de memoria, pero mas o menos

Esto en mi caso se hace de esta forma:

Código:
Session session = SessionHibernate.getInstance().getSession();

Y por detrás hace el mismo openSession() Wink

La respuesta 100% satisfactoria, ajusté un poco las cosas tal como me explicó y funciona perfecto Smile

Cualquier duda pueden preguntar.

PD: Trabajar con Hibernate resulta bastante satisfactorio después de haber usado los "horribles" DAOs jajajajaja Big Grin

[Imagen: raxn5j.jpg]
18-11-2011 11:17 PM
Visita su sitio web Encuentra todos sus mensajes Cita este mensaje en tu respuesta
demian Sin conexión
Administrator
*******

Mensajes: 1.808
Registro en: Jun 2010
Reputación: 0
Mensaje: #2
RE: Ayuda para cargar listas desde BD [Resuelto]
Me alegra que haya funcionado Smile
Gracias por publicarlo aquí, estoy seguro que a tus compañeros les va a ser útil, los errores de Lazy Loading son bastante comunes en Hibernate, saber arreglarlos y comprender la lógica detrás del asunto es importante.

[Imagen: dmi-1.jpg]
19-11-2011 11:21 AM
Visita su sitio web Encuentra todos sus mensajes Cita este mensaje en tu respuesta
Enviar respuesta 


Salto de foro:


Usuario(s) navegando en este tema: 1 invitado(s)