Foros del Web » Programación para mayores de 30 ;) » Java »

Duda con JPA

Estas en el tema de Duda con JPA en el foro de Java en Foros del Web. Saludos Comunidad Foros del Web, nuevamente recurro a ustedes en busca de algunas ideas. Estoy haciendo unas cosillas con JPA y me pasa algo que ...
  #1 (permalink)  
Antiguo 10/12/2012, 20:49
Avatar de farfamorA  
Fecha de Ingreso: noviembre-2010
Ubicación: Lima
Mensajes: 136
Antigüedad: 13 años, 4 meses
Puntos: 24
Duda con JPA

Saludos Comunidad Foros del Web, nuevamente recurro a ustedes en busca de algunas ideas. Estoy haciendo unas cosillas con JPA y me pasa algo que me está intrigando mucho.
Veamos, estoy usando EclipseLink (JPA 2.0) y una base de datos Apache Derby embebida.
Básicamente, lo que necesito es crear (muchos) otros objetos a partir de una lista de la entidad Curso. En este proceso de creación, siempre voy a usar la lista de cursos original, es decir, no necesito (y no quiero, por un tema de eficiencia) consultar una y otra vez a la base de datos para que me devuelva la misma lista. Quiero usar siempre la misma instancia para generar mis otros objetos.
Para esto, uso el patrón Singleton:
Código Java:
Ver original
  1. // Método Singleton
  2.     private List<Curso> listaCursos;
  3.  
  4.     public List<Curso> getListaCursos() throws DaoException {
  5.         if ( listaCursos == null ) {
  6.            listaCursos = new CursoDao().traerTodos();
  7.         }
  8.         return listaCursos;
  9.     }
Hasta ahí todo bien, sólo hace la consulta a la base de datos la primera vez (cuando listaCursos es nulo).

El problema viene a continuación:

Creo un List de la entidad Curso llamado listaCursos1 y en esta lista guardo la lista de cursos.
Código Java:
Ver original
  1. // Instancia lista de cursos
  2.     List<Curso> listaCursos1;
  3.     listaCursos1 = Utilitarios.getInstance().getListaCursos();
Itero la listaCursos1, le hago algunos cambios (le "seteo" otras valores a sus atributos).
Creo una nueva lista de cursos llamada listaCursos2.
Código Java:
Ver original
  1. // Instancia nueva lista de cursos
  2.     List<Curso> listaCursos2;
  3.     listaCursos2 = Utilitarios.getInstance().getListaCursos();
Ahora, pasa que la listaCursos2 no es igual a lista original (la del patrón singleton, la que viene de la base de datos), sino que es igual a la listaCursos1. Todos los cambios que he realizado a la listaCursos1 se han realizado también sobre la listaCursos original. ¿Por qué pasa eso?

Adjunto el método que me devuelve la lista de cursos desde la base de datos.
Código Java:
Ver original
  1. // Método que devuelve la lista de todos los cursos
  2.     public List<Curso> traerTodos() throws DaoException {
  3.         em = getEntityManager();
  4.         List<Curso> cursos;
  5.         try {
  6.             Query q = em.createQuery("SELECT c FROM Curso c ORDER BY c.codigo ASC");
  7.             cursos = q.getResultList();
  8.             logger.log(Level.INFO, "Lista de cursos devuelta satisfactoriamente ({0})", cursos.size());
  9.         } catch(Exception ex){
  10.             logger.log(Level.WARNING, ex.getMessage(), ex);
  11.             throw new DaoException("Error al traer Lista de Cursos:" + ex.getMessage(), ex);
  12.         } finally {
  13.             if (em != null && em.isOpen()) {
  14.                 em.close();
  15.             }
  16.         }
  17.         return cursos;
  18.     }
El EntityManager se cierra al finalizar y se manejan las excepciones.

Acá un pequeño ejemplo de mi problema:
Código Java:
Ver original
  1. // Ejemplo
  2.     public static void main(String[] args) {
  3.         try {
  4.             FactoryDao factoryDao = new FactoryDao();
  5.            
  6.             List<Curso> listaCursos1;
  7.             listaCursos1 = Utilitarios.getInstance().getListaCursos();
  8.             System.out.println("Lista Original: " + listaCursos1);
  9.            
  10.             // Hago algunos cambios sobre la listaCursos1
  11.             listaCursos1.remove(0);
  12.             System.out.println("Lista Cursos 1: " + listaCursos1);
  13.            
  14.             // Creo una nueva lista
  15.             List<Curso> listaCursos2;
  16.             listaCursos2 = Utilitarios.getInstance().getListaCursos();
  17.             // La (nueva) lista 2 refleja los cambios que se le hicieron a la lista 1.
  18.             System.out.println("Lista Cursos 2: " + listaCursos2);
  19.         } catch (Exception e) {
  20.             e.printStackTrace();
  21.         }
  22.     }

Y no entiendo por qué pasa eso, ¿qué podría hacer para salvar esta situación?
Gracias por su atención, espero ansioso sus observaciones.
  #2 (permalink)  
Antiguo 11/12/2012, 05:53
Avatar de Fuzzylog  
Fecha de Ingreso: agosto-2008
Ubicación: En internet
Mensajes: 2.511
Antigüedad: 15 años, 7 meses
Puntos: 188
Respuesta: Duda con JPA

Creo que es porque las referencias tanto de listaCursos como de listaCursos1 apuntan al mismo objeto (la lista de cursos original).

Para ese caso, modifica el patrón singleton. Si puedes clonar el objeto bien. Si no, crea una nueva lista, vuelca todos los objetos de la listaCursos original en ella y retorna esa nueva lista.

Un saludo.
__________________
if (fuzzy && smooth) {
fuzzylog = "c00l";
return true;
}
  #3 (permalink)  
Antiguo 11/12/2012, 09:18
Avatar de farfamorA  
Fecha de Ingreso: noviembre-2010
Ubicación: Lima
Mensajes: 136
Antigüedad: 13 años, 4 meses
Puntos: 24
Respuesta: Duda con JPA

Hola Fuzzylog, gracias por responder.
Implementé tus recomendaciones y mi método singleton quedó así:
Código Javascript:
Ver original
  1. // Método singleton
  2.     private List<Curso> getListaCursos() throws DaoException {
  3.         if ( listaCursos == null ) {
  4.             listaCursos = new CursoDao().traerTodos();
  5.         }
  6.         List<Curso> nuevaLista = new ArrayList<Curso>();
  7.         for (Iterator<Curso> it = listaCursos.iterator(); it.hasNext();) {
  8.             Curso curso;
  9.             curso = it.next();
  10.             nuevaLista.add(curso);
  11.         }
  12.         return nuevaLista;
  13.     }
Gracias a esta modificación, el método del ejemplo anterior ahora arroja los resultados esperados. Remuevo el primer elemento de listaCursos1, y la listaCursos2 aparece completa.
Output:
Código:
Lista Original: [960001, 960002, 960003, 960004, 960005]
Lista Cursos 1: [960002, 960003, 960004, 960005]
Lista Cursos 2: [960001, 960002, 960003, 960004, 960005]

Pero el panorama cambia cuando no remuevo, sino cuando "seteo" nuevos valores a sus atributos. Pero en este punto me he dado cuenta que no tiene nada que ver con JPA. Cuando completo la listaCursos "manualmente", es decir, sin hacer consulta a la base de datos, también tengo ese problema.
Ejemplo 2.
Código Javascript:
Ver original
  1. //
  2.     private List<Curso> listaCursosManual;
  3.    
  4.     // Método que devuelve una Lista de Cursos, completados de manera "manual"
  5.     // Hace las veces de la consulta a la base de datos
  6.     private List<Curso> popularListaCursos() {
  7.         List<Curso> lista;
  8.         lista = new ArrayList<Curso>();
  9.         Curso curso;
  10.         for (int i = 1; i < 6; i++) {
  11.             curso = new Curso(i);
  12.             curso.setCodigo("96000"+i);
  13.             lista.add(curso);
  14.         }
  15.         return lista;
  16.     }
  17.     // Método patrón Singleton
  18.     private List<Curso> getListaCursosManual() throws DaoException {
  19.         if ( listaCursosManual == null ) {
  20.             listaCursosManual = popularListaCursos();
  21.         }
  22.         List<Curso> nuevaLista = new ArrayList<Curso>();
  23.         for (Iterator<Curso> it = listaCursosManual.iterator(); it.hasNext();) {
  24.             Curso curso;
  25.             curso = it.next();
  26.             nuevaLista.add(curso);
  27.         }
  28.         return nuevaLista;
  29.     }    
  30.     // Ejemplo
  31.     public static void main(String[] args) {
  32.         try {
  33.             List<Curso> listaCursos1;
  34.             listaCursos1 = Utilitarios.getInstance().getListaCursosManual();
  35.             System.out.println("Lista Original: " + listaCursos1);
  36.             // Hago algunos cambios sobre la listaCursos1
  37.             listaCursos1.get(0).setCodigo("XXXXXX");
  38.             System.out.println("Lista Cursos 1: " + listaCursos1);
  39.  
  40.             // Creo una nueva lista
  41.             List<Curso> listaCursos2;
  42.             listaCursos2 = Utilitarios.getInstance().getListaCursosManual();
  43.  
  44.             // La (nueva) lista 2 refleja los cambios que se le hicieron a la lista 1.
  45.             System.out.println("Lista Cursos 2: " + listaCursos2);
  46.        
  47.         } catch (Exception e) {
  48.             e.printStackTrace();
  49.         }
  50.     }
Output:
Código:
Lista Original: [960001, 960002, 960003, 960004, 960005]
Lista Cursos 1: [XXXXXX, 960002, 960003, 960004, 960005]
Lista Cursos 2: [XXXXXX, 960002, 960003, 960004, 960005]

No me doy cuenta dónde lo estoy haciendo mal...
Muchas gracias por su tiempo.

Etiquetas: jpa, singleton
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 17:36.