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

[SOLUCIONADO] Problema aplicación JSF + EJB + Schedule Primefaces

Estas en el tema de Problema aplicación JSF + EJB + Schedule Primefaces en el foro de Java en Foros del Web. Hola, estoy creando una aplicación JSF con EJB + JPA, y tengo un problema (más bien es desconocimiento de la tecnología, ya que soy nuevo ...
  #1 (permalink)  
Antiguo 11/11/2013, 16:16
 
Fecha de Ingreso: noviembre-2013
Mensajes: 26
Antigüedad: 10 años, 5 meses
Puntos: 0
Problema aplicación JSF + EJB + Schedule Primefaces

Hola, estoy creando una aplicación JSF con EJB + JPA, y tengo un problema (más bien es desconocimiento de la tecnología, ya que soy nuevo en esto). El problema es con el componente Schedule de Primefaces.

Yendo a lo básico, tengo guardado en una Lista una serie de Citas (la aplicación es la gestión de una peluquería). Para cargar los eventos al calendario, hago lo siguiente (funciona correctamente):

Código:
@PostConstruct
    public void init(){
       
            List<Cita> citas;
            citas = citaLN.recuperarTodasCitas();
            System.out.println(citas.get(0).getFechaIni());
            System.out.println(citas.get(0).getFechaFin());
            for (int i = 0; i < citas.size(); i++){
                eventModel.addEvent(new DefaultScheduleEvent(citas.get(i).getNombre(), citas.get(i).getFechaIni(), citas.get(i).getFechaFin(), citas.get(i)));   
            }     
            
    }
El problema lo tengo al hacer un resize o mover el evento a otra hora, que hago lo siguiente:

Código:
public void onEventMove(ScheduleEntryMoveEvent event) {  
        List<Cita> listaCitas = citaLN.recuperarTodasCitas();
        System.out.println(listaCitas.get(0).getFechaIni());
        System.out.println(listaCitas.get(0).getFechaFin());
        
        FacesMessage message = new    FacesMessage(FacesMessage.SEVERITY_INFO, "Event moved", "Day delta:" + event.getDayDelta() + ", Minute delta:" + event.getMinuteDelta());  
        addMessage(message);  
        
        ScheduleEvent ev = event.getScheduleEvent();  
        
        Cita cita = (Cita) ev.getData();
 
        citaLN.modificarCita(cita);

        
    }
Como apunte, citaLN es un session bean, y con el método recuperarTodasCitas() me devuelve el listado de citas almacenadas en la BD (esto funciona correctamente). Lo mismo con modificarCita(Cita), actualiza la cita en la BD.

Como podéis ver, en la llamada para iniciar, hago dos Print, donde muestro la única cita que tengo guardada en la BD, y el resultado es: Mon Nov 11 11:00:00 CET 2013 y Mon Nov 11 12:00:00 CET 2013 (fecha de inicio y fin de la cita). Hasta aquí todo correcto, el problema es al mover el evento por ejemplo 1 hora más tarde, los print que me muestra son Mon Nov 11 12:00:00 CET 2013 y Mon Nov 11 13:00:00 CET 2013.

Esto para mí no tiene sentido, ya que lo que estoy mostrando en los print de el evento onEventMove es la misma llamada que en la función de inicializar. Una llamada la BD que me devuelve la lista de Citas. Es decir, parece que ya esté modificado cuando a mi parecer no debería de estarlo.

El problema es que al hacer citaLN.modificarCita(cita), no realiza la modificación, y he llegado a la conclusión que no lo hace porque al igual que el método de citaLN.recuperarTodasCitas() sale como modificado, aquí también, y no modifica la cita porque ve que es la misma.

He creado otro método para guardar en esa cita los valores que tenía el evento antes de moverlo, es decir de 11 a 12, y luego modificarlo de nuevo con los valores nuevos (de 12 a 13), y así sí que me guarda en la base de datos la modificación.

Esta solución es bastante cutre, y me gustaría poder solucionarlo de una forma correcta y saber por qué pasa esto. Lo más seguro es que sea un fallo conceptual mío de base, por eso pregunto a ver si algún sabio de este tema me puede ayudar a entender el comportamiento.

Un saludo y gracias!
  #2 (permalink)  
Antiguo 11/11/2013, 21:43
Avatar de HackmanC  
Fecha de Ingreso: enero-2008
Ubicación: Guatemala
Mensajes: 1.817
Antigüedad: 16 años, 2 meses
Puntos: 260
Sonrisa Respuesta: Problema aplicación JSF + EJB + Schedule Primefaces

Hola,

Posiblemente, revisa los logs para ver si no estas actualizando varias veces, es decir, es normal en JSF que los métodos se llamen muchas veces aunque realicen la misma actividad. Y mas de alguna ves sucede que al generar mucha información en los logs se observe solo las últimas líneas. Por ejemplo, en un DataTable JSF puede llamar al metodo getData() (o como se llame) varias veces en un solo rendering, por eso es importante cachear la info.

La otra es que no sabemos que hay dentro del método "citaLN.modificarCita(cita);", si estas usando persist(), merge() o alguna otra cosa. Dependiendo de algunos factores, si la entidad está 'detached' no la va a actualizar porque no sabe cual es, normalmente, primero obtienes el Entity a actualizar, después lo actualizas con los setters, y por último lo haces persistente.

Saludos,
  #3 (permalink)  
Antiguo 12/11/2013, 01:42
 
Fecha de Ingreso: noviembre-2013
Mensajes: 26
Antigüedad: 10 años, 5 meses
Puntos: 0
Respuesta: Problema aplicación JSF + EJB + Schedule Primefaces

Hola Hackman, gracias por contestar.

Te comento, lo que hace citaLN.modificarCita precisamente es un merge. El método es el siguiente:

Código:
public List<Cita> recuperarTodasCitas(){
        return citaFacade.findAll();
    }
En citaFacade.finAll() hace un merge.

Lo primero que comentas no me queda muy claro, pero no parece ser que tenga que ver con el problema. El tema es que en cuanto hago un evento de mover la cita, el método recuperarTodasCitas me devuelve el listado con la cita MODIFICADA ya. Como si de la BD lo leyera modificado. Por lo tanto al usar modificarCita, parece ser que ve que está modificada y no lo cambia en la BD.

La verdad es que no entiendo este comportamiento y me está volviendo loco.

Un saludo.
  #4 (permalink)  
Antiguo 12/11/2013, 21:34
Avatar de HackmanC  
Fecha de Ingreso: enero-2008
Ubicación: Guatemala
Mensajes: 1.817
Antigüedad: 16 años, 2 meses
Puntos: 260
Sonrisa Respuesta: Problema aplicación JSF + EJB + Schedule Primefaces

Hola,

Posiblemente,

Cita:
Iniciado por malome88 Ver Mensaje
En citaFacade.finAll() hace un merge.
¿Por qué en un findAll pones un merge?

Si el método se llama findAll debería solamente hacer un Query donde busca todos los registros o entities y devolver una colección de estos. Si cada vez que llamas a recuperarTodasCitas(), llama a findAll y allí hace un merge() entonces (posiblemente) ya estás persistiendo la información y por eso devuelve las entidades ya modificadas.

Por ejemplo:

Cita:
Iniciado por malome88 Ver Mensaje
[CODE]
eventModel.addEvent(new DefaultScheduleEvent(citas.get(i).getNombre(), citas.get(i).getFechaIni(), citas.get(i).getFechaFin(), citas.get(i)));
El último parámetro es la Entidad y esa entidad está 'attached'.

Cita:
Iniciado por malome88 Ver Mensaje
Código:
        
public void onEventMove(ScheduleEntryMoveEvent event) {  
        List<Cita> listaCitas = citaLN.recuperarTodasCitas();
...
        Cita cita = (Cita) ev.getData();
        citaLN.modificarCita(cita);
    }
Si en recuperarTodasCitas() hay un merge, en ese momento se hace persistente. (El merge busca una Entidad attached con el mismo Id y la actualiza). Cuando llega a modificarCita() ya está actualizada la cita.

Saludos,
  #5 (permalink)  
Antiguo 13/11/2013, 02:59
 
Fecha de Ingreso: noviembre-2013
Mensajes: 26
Antigüedad: 10 años, 5 meses
Puntos: 0
Respuesta: Problema aplicación JSF + EJB + Schedule Primefaces

Perdón, me he equivocado al redactar el mensaje.

El que hace un merge es modificarCita.

El recuperarTodasCitas llama a findAll() que hace un find que devuelve el listado de citas de la BD. NO hace un merge, me he equivocado al escribirlo.

De ahí que no entienda que pasa, que el findAll me devuelva el listado con la cita modificada, cuando en la BD no está modificada y ese método lee directamente de la BD...

Me lleva loco este tema
  #6 (permalink)  
Antiguo 13/11/2013, 22:29
Avatar de HackmanC  
Fecha de Ingreso: enero-2008
Ubicación: Guatemala
Mensajes: 1.817
Antigüedad: 16 años, 2 meses
Puntos: 260
Sonrisa Respuesta: Problema aplicación JSF + EJB + Schedule Primefaces

Hola,

Cita:
Iniciado por malome88 Ver Mensaje
Perdón, me he equivocado al redactar el mensaje.
Me lo imaginé, pero no estaba seguro. Ahora que está todo un poco mas claro el problema creo que se puede comprobar fácilmente:

Código Java:
Ver original
  1. @Test
  2.     public void test() {
  3.         EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("LIB-TPU");
  4.         EntityManager entityManager = entityManagerFactory.createEntityManager();
  5.  
  6.         CriteriaQuery<Object> criteriaQuery = entityManager.getCriteriaBuilder().createQuery();
  7.         criteriaQuery.select(criteriaQuery.from(SimpleEntity.class));
  8.         Query query = entityManager.createQuery(criteriaQuery);
  9.  
  10.         @SuppressWarnings("unchecked")
  11.         List<SimpleEntity> result = query.getResultList();
  12.         for (SimpleEntity simpleEntity : result) {
  13.             LOG.debug("{}", simpleEntity);
  14.         }
  15.  
  16.         result.get(0).setNombre("Nuevo nombre");
  17.  
  18.         CriteriaQuery<Object> criteriaQuery2 = entityManager.getCriteriaBuilder().createQuery();
  19.         criteriaQuery2.select(criteriaQuery2.from(SimpleEntity.class));
  20.         Query query2 = entityManager.createQuery(criteriaQuery2);
  21.  
  22.         @SuppressWarnings("unchecked")
  23.         List<SimpleEntity> result2 = query2.getResultList();
  24.         for (SimpleEntity simpleEntity : result2) {
  25.             LOG.debug("{}", simpleEntity);
  26.         }
  27.  
  28.         entityManager.merge(result.get(0));
  29.         entityManager.merge(result2.get(0));
  30.         entityManager.close();
  31.     }

.....
  #7 (permalink)  
Antiguo 13/11/2013, 22:30
Avatar de HackmanC  
Fecha de Ingreso: enero-2008
Ubicación: Guatemala
Mensajes: 1.817
Antigüedad: 16 años, 2 meses
Puntos: 260
Sonrisa Respuesta: Problema aplicación JSF + EJB + Schedule Primefaces

.....
Ese es un test de una librería personal, y el resultado es parecido a esto:

Código:
2013-11-13 21:49:24,527 DEBUG [main] com.....[codigo='1'][nombre='primero']
2013-11-13 21:49:24,543 DEBUG [main] com....[codigo='1'][nombre='Nuevo nombre']
Alli se puede observar que el segundo LOG muestra la entidad modificada pero no se hace persistente en la base de datos, la base de datos no se actualizó nunca; aun cuando se hace merge() de los dos resultados al final. El problema estriba en que JPA maneja un estado interno de las entidades, al hacer un findAll() en tu caso seguramente hace un merge interno (por decirlo de alguna forma), que es lo que sucede en este caso también.

Igual no tiene mucho sentido hacer un findAll() y después otro findAll() de la misma data, por eso lo tienes en un Session Bean, a menos que sea demasiada data en sesión u otros motivos.

Saludos,
  #8 (permalink)  
Antiguo 13/11/2013, 23:05
Avatar de HackmanC  
Fecha de Ingreso: enero-2008
Ubicación: Guatemala
Mensajes: 1.817
Antigüedad: 16 años, 2 meses
Puntos: 260
Sonrisa Respuesta: Problema aplicación JSF + EJB + Schedule Primefaces

Hola,

Revisando de nuevo la prueba, creo que olvidé las transacciones, en Java JSE las transacciones no son automáticas. Revisa que estés obteniendo tu EntityManager de forma transaccional y que se realice el commit() al final.

Saludos,
  #9 (permalink)  
Antiguo 14/11/2013, 05:59
 
Fecha de Ingreso: noviembre-2013
Mensajes: 26
Antigüedad: 10 años, 5 meses
Puntos: 0
Respuesta: Problema aplicación JSF + EJB + Schedule Primefaces

Muchas gracias de nuevo por tu respuesta.

Decir que lo de hacer un nuevo findAll() lo he hecho para mostrar el "problema". El segundo findAll() se quitará en el caso real.

Por los resultados que me pones del log, veo que pasa lo mismo, parece que la segunda vez lee de la BD pero realmente no está leyendo de ahí, sino de una especie de estado interno ( y de verdad que no entiendo este comportamiento, no le veo ningún tipo de sentido).

El problema es que al leer este estado interno que comentas digamos que ve que la BD está ya modificada ( realmente no lo está como te he comentado), y al hacer el citaLN.modificarCita(cita) que es el que realmente hace el merge no me actualiza la BD (supongo que ve que ya tiene los mismos datos, cuando no es así a causa del "estado interno" que parece que hace).

  #10 (permalink)  
Antiguo 14/11/2013, 21:05
Avatar de HackmanC  
Fecha de Ingreso: enero-2008
Ubicación: Guatemala
Mensajes: 1.817
Antigüedad: 16 años, 2 meses
Puntos: 260
Sonrisa Respuesta: Problema aplicación JSF + EJB + Schedule Primefaces

Hola,

Cita:
Iniciado por malome88 Ver Mensaje
Decir que lo de hacer un nuevo findAll() lo he hecho para mostrar el "problema". El segundo findAll() se quitará en el caso real.

Por los resultados que me pones del log, veo que pasa lo mismo, parece que la segunda vez lee de la BD pero realmente no está leyendo de ahí, sino de una especie de estado interno ( y de verdad que no entiendo este comportamiento, no le veo ningún tipo de sentido).
Exactamente, el segundo findAll ya tiene esa entidad.

Cita:
Iniciado por malome88 Ver Mensaje
El problema es que al leer este estado interno que comentas digamos que ve que la BD está ya modificada ( realmente no lo está como te he comentado), y al hacer el citaLN.modificarCita(cita) que es el que realmente hace el merge no me actualiza la BD (supongo que ve que ya tiene los mismos datos, cuando no es así a causa del "estado interno" que parece que hace).
Así es, el comportamiento es el mismo, traté de replicar el problema con un Test que ya tenía hecho y presenta exactamente lo que describes. Pero, eso fue antes de recordarme que en el Test es lógico que no funcione, puesto que me hacía falta poner un begin() y un commit(). Luego de agregar eso al Test funciona correctamente, es decir, presenta el mismo comportamiento que describiste pero si lo hace persistente en la base de datos en la llamada al merge().

Por último revisa el persistence.xml para ver si estas usando JTA y no RESOURCE_LOCAL.

Creo que se me acabaron las ideas al respecto, posiblemente alguien con mayor experiencia en Prime y ese componente sea de mayor ayuda,

Saludos,
  #11 (permalink)  
Antiguo 15/11/2013, 09:09
 
Fecha de Ingreso: noviembre-2013
Mensajes: 26
Antigüedad: 10 años, 5 meses
Puntos: 0
Respuesta: Problema aplicación JSF + EJB + Schedule Primefaces

He mirado y pone JTA. Respecto a lo que me comentas que falta en el ejemplo para que "funcion", que es? Es que no se a que te refieres.

Código:
    public void modificarCita(Cita cita) {
        citaFacade.edit(cita);
    }
Código:
@Stateless
public class CitaFacade extends AbstractFacade<Cita> {
    @PersistenceContext(unitName = "Mega-ejbPU")
    private EntityManager em;

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

    public CitaFacade() {
        super(Cita.class);
    }
    
}
Código:
public abstract class AbstractFacade<T> {
    private Class<T> entityClass;

    public AbstractFacade(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    protected abstract EntityManager getEntityManager();

    public void create(T entity) {
        getEntityManager().persist(entity);
    }

    public void edit(T entity) {
        getEntityManager().merge(entity);
    }

    public void remove(T entity) {
        getEntityManager().remove(getEntityManager().merge(entity));
    }

    public T find(Object id) {
        return getEntityManager().find(entityClass, id);
    }

    public List<T> findAll() {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        return getEntityManager().createQuery(cq).getResultList();
    }
}
Ahí te pongo todos los métodos, para que veas exactamente lo que hace. Las clases Facade son generadas automáticamente en netbeans creado un Session Beans for Entity Classes.
  #12 (permalink)  
Antiguo 17/11/2013, 01:43
Avatar de HackmanC  
Fecha de Ingreso: enero-2008
Ubicación: Guatemala
Mensajes: 1.817
Antigüedad: 16 años, 2 meses
Puntos: 260
Sonrisa Respuesta: Problema aplicación JSF + EJB + Schedule Primefaces

Hola,

Prueba a modificar la Entity.

Código:
    ....
    @Mutable(true)
    private Date fechaIni;

    ....
    @Mutable(true)
    private Date fechaFin;
Saludos,
  #13 (permalink)  
Antiguo 17/11/2013, 04:33
 
Fecha de Ingreso: noviembre-2013
Mensajes: 26
Antigüedad: 10 años, 5 meses
Puntos: 0
Respuesta: Problema aplicación JSF + EJB + Schedule Primefaces

Hola, he probado lo que dices pero da error: Cannot find symbol. Symbol: class mutable. Location: class Cita
  #14 (permalink)  
Antiguo 17/11/2013, 13:04
Avatar de HackmanC  
Fecha de Ingreso: enero-2008
Ubicación: Guatemala
Mensajes: 1.817
Antigüedad: 16 años, 2 meses
Puntos: 260
Sonrisa Respuesta: Problema aplicación JSF + EJB + Schedule Primefaces

Hola,

Cita:
Iniciado por malome88 Ver Mensaje
Hola, he probado lo que dices pero da error: Cannot find symbol. Symbol: class mutable. Location: class Cita
Me refería a que si estas usando EclipseLink tienes que agregar la dependencia o la librería al proyecto, importar el package correspondiente en la clase, después hacer las modificaciones, posteriormente compilar todo el proyecto y por último hacer el deploy de nuevo en el servidor de aplicaciones.

Código Java:
Ver original
  1. import org.eclipse.persistence.annotations.Mutable;
  2. ....
  3.     @Basic(optional = false)
  4.     @Column(nullable = false)
  5.     @Temporal(TemporalType.DATE)
  6.     @Mutable(true)
  7.     private Date fecini;
  8. ....
  9.     @Basic(optional = false)
  10.     @Column(nullable = false)
  11.     @Temporal(TemporalType.DATE)
  12.     @Mutable(true)
  13.     private Date fecfin;

Para comprobarlo realicé todo el ejercicio en un proyecto, logré reproducir el comportamiento que describiste desde el primer post, y se corrigió el problema al agregar lo anterior. Si no estas usando EclipseLink entonces no tengo ni idea.

Saludos,
  #15 (permalink)  
Antiguo 21/11/2013, 13:09
 
Fecha de Ingreso: noviembre-2013
Mensajes: 26
Antigüedad: 10 años, 5 meses
Puntos: 0
Respuesta: Problema aplicación JSF + EJB + Schedule Primefaces

Muchas gracias! Acabo de probar esto último que comentas y por fin me ha funcionado.

He añadido lo siguiente al persistence.xml:

<properties>
<property name="eclipselink.temporal.mutable" value="true"/>
</properties>

De esta forma ha funcionado, pero no entiendo que es lo que hace esto ni que estaba pasando.

Insisto, gracias porque son cosas que al final te vuelven loco!
  #16 (permalink)  
Antiguo 21/11/2013, 20:46
Avatar de HackmanC  
Fecha de Ingreso: enero-2008
Ubicación: Guatemala
Mensajes: 1.817
Antigüedad: 16 años, 2 meses
Puntos: 260
Sonrisa Respuesta: Problema aplicación JSF + EJB + Schedule Primefaces

Hola,

Cita:
Iniciado por malome88 Ver Mensaje
... De esta forma ha funcionado, pero no entiendo que es lo que hace esto ni que estaba pasando. ...
http://www.eclipse.org/eclipselink/d.../a_mutable.htm

Saludos,

Etiquetas: ejb, jsf, primefaces
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 08:10.