6 Replies Latest reply on Sep 18, 2008 4:44 PM by maykell.mflores.uci.cu

    Lazy loading problem

    maykell.mflores.uci.cu

      Hi all, i have a problema with lazy loading i think.


      I have an ordinary entity that have a collection of items, the getItems() method is annotated with fetchType.Lazy, the problem is that when i persist an item an go back to the entity detail page, and click on the tab that shows the list of items assosiated with the entity, the list is returning empty, nevertheless if i go to the menu bar(my project is a seam-gen generated one) and click on the entityList option, everything works just fine, the tab shows the collection of items without problem.
      There is another clue, if i go again and add another item and go back to the entity detail page i get the tab showing the collection minus the last item that was persisted.


      Somebody can explain me this behavior.


      This is my code:
      the entity class:


      package com.prueba.domain;
      
      import java.util.ArrayList;
      import java.util.List;
      
      import javax.persistence.CascadeType;
      import javax.persistence.Column;
      import javax.persistence.Entity;
      import javax.persistence.FetchType;
      import javax.persistence.GeneratedValue;
      import javax.persistence.Id;
      import javax.persistence.OneToMany;
      import javax.persistence.Table;
      
      import org.hibernate.validator.NotNull;
      import org.jboss.seam.annotations.AutoCreate;
      import org.jboss.seam.annotations.Name;
      
      
      @Name("expediente")
      @Entity
      @Table (name="EXPEDIENTE")
      public class Expediente {
              
              private Long id;
          private String nroExpediente;
          private List<Testigo> testigos = new ArrayList<Testigo>();
          private List<Acusado> acusados = new ArrayList<Acusado>();
          
          
          @OneToMany(cascade = CascadeType.ALL ,fetch = FetchType.LAZY, mappedBy="expediente")
          public List<Acusado> getAcusados() {
                      return acusados;
              }
      
              public void setAcusados(List<Acusado> acusados) {
                      this.acusados = acusados;
              }
      
              @Column (name="nroExpediente", nullable = false)
          @NotNull
              public String getNroExpediente() {
                      return nroExpediente;
              }
      
              public void setNroExpediente(String nroExpediente) {
                      this.nroExpediente = nroExpediente;
              }
      
              @Id
              @GeneratedValue
              public Long getId() {
                      return id;
              }
      
              public void setId(Long id) {
                      this.id = id;
              }
      
              @OneToMany(cascade=CascadeType.ALL,fetch = FetchType.LAZY, mappedBy = "expediente")
              public List<Testigo> getTestigos() {
                      return testigos;
              }
      
              public void setTestigos(List<Testigo> testigoLista) {
                      this.testigos = testigoLista;
              }
      
      }
      



      The item class:


      package com.prueba.domain;
      
      import javax.persistence.Column;
      import javax.persistence.Entity;
      import javax.persistence.FetchType;
      import javax.persistence.JoinColumn;
      import javax.persistence.ManyToOne;
      import javax.persistence.NoResultException;
      import javax.persistence.NonUniqueResultException;
      import javax.persistence.PrimaryKeyJoinColumn;
      import javax.persistence.Table;
      
      import org.hibernate.validator.NotNull;
      import org.jboss.seam.ScopeType;
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.annotations.Scope;
      import org.jboss.seam.annotations.web.RequestParameter;
      
      @Name("acusado")
      @Entity
      @PrimaryKeyJoinColumn(name="PERSONA_ID")
      @Table (name="ACUSADO")
      public class Acusado extends Persona {
              
              private String descripcionFisica;
              private Expediente expediente;
      
      
              @ManyToOne (fetch = FetchType.LAZY)
              @JoinColumn(name="Expediente_ID",nullable = false)
              public Expediente getExpediente() {
                      return expediente;
              }
      
              public void setExpediente(Expediente expediente) {
                      this.expediente = expediente;
              }
      
              @Column (name="descripcionFisica", nullable = false)
          @NotNull
              public String getDescripcionFisica() {
                      return descripcionFisica;
              }
      
              public void setDescripcionFisica(String descripcionFisica) {
                      this.descripcionFisica = descripcionFisica;
              }
              
      
      
      }
      
      



      The entityHome class:


      package com.prueba.facade;
      
      import java.util.ArrayList;
      import java.util.List;
      
      import org.jboss.seam.annotations.In;
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.annotations.Begin;
      import org.jboss.seam.annotations.Out;
      import org.jboss.seam.annotations.Transactional;
      import org.jboss.seam.annotations.web.RequestParameter;
      import org.jboss.seam.framework.EntityHome;
      
      import com.prueba.domain.Acusado;
      import com.prueba.domain.Expediente;
      
      @Name("expedienteHome")
      public class ExpedienteHome extends EntityHome<Expediente> {
      
              @RequestParameter
              Long expedienteId;
              
              @Out 
              List<Acusado> listaAcusados = new ArrayList<Acusado>();
      
              @Override
              public Object getId() {
                      if (expedienteId == null) {
                              return super.getId(); 
                      } else {
                              return expedienteId;
                      }
              }
      
              @Override
              @Begin
              public void create() {
                      super.create();
      
              }
      
              @Transactional
              public List<Acusado> getAcusados() {
                      if (getInstance() == null)
                              return null;
                      else {
                              Object lista = getInstance().getAcusados();
                              this.listaAcusados = (List<Acusado>)lista;
                              return (List<Acusado>)lista;
                      }
              }
      
      }
      



      The itemAction class:


      package com.prueba.facade;
      
      import java.io.Serializable;
      
      import javax.persistence.EntityManager;
      import javax.persistence.NoResultException;
      import javax.persistence.NonUniqueResultException;
      
      import org.jboss.seam.Component;
      import org.jboss.seam.ScopeType;
      import org.jboss.seam.annotations.Begin;
      import org.jboss.seam.annotations.Conversational;
      import org.jboss.seam.annotations.FlushModeType;
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.annotations.In;
      import org.jboss.seam.annotations.Logger;
      import org.jboss.seam.annotations.Out;
      import org.jboss.seam.annotations.Scope;
      import org.jboss.seam.annotations.Transactional;
      import org.jboss.seam.annotations.web.RequestParameter;
      import org.jboss.seam.core.Events;
      import org.jboss.seam.log.Log;
      import org.jboss.seam.faces.FacesMessages;
      
      import com.prueba.domain.Acusado;
      import com.prueba.domain.Expediente;
      
      @Name("registerAcusadoAction")
      @Scope(ScopeType.CONVERSATION)
      public class RegisterAcusadoAction implements Serializable{
      
              @Logger
              private Log log;
              @In
              FacesMessages facesMessages;
              @In
              private EntityManager entityManager;
              
              @RequestParameter
              String kaka;
              
              @RequestParameter
              String returnTo = "testigoList.xhtml";
              
              String from = "/acusadoList.xhtml";
      
              @Out(required = false) Acusado acusado;
              
              @In (create = true)
              ExpedienteHome expedienteHome;
      
      
              @Transactional
              @Begin(join=true)
              public void registerAcusado(Acusado acusadoLocal) {
                      acusadoLocal.setExpediente(expedienteHome.getInstance());
                      entityManager.persist(acusadoLocal);
                      entityManager.flush();
                      acusado = acusadoLocal;
                      Events.instance().raiseTransactionSuccessEvent("EntidadCRUD","Acusado Registrado", "RegisterAcusadoAction.registerAcusado");
              }
      
              
              public void updateAcusado(Acusado acusadoLocal) {
                      boolean bol1 = entityManager.contains(acusadoLocal);
                      entityManager.flush();
      //              Events.instance().raiseTransactionSuccessEvent("EntidadCRUD","Acusado Actualizado", "RegisterAcusadoAction.updateAcusado");
              }
      
              @Transactional
              public void loadAcusado() { 
                      Events.instance().raiseTransactionSuccessEvent("EntidadCRUD","", "RegisterAcusadoAction.loadAcusado");
                      if (kaka != null ) {   
                              try {
                                      acusado = (Acusado) entityManager.find(Acusado.class, kaka);
                              } catch (NoResultException nre) {
                              } catch (NonUniqueResultException nure) {
                              }
                      }else
                      {
                              boolean bol1 = entityManager.contains(Component.getInstance("acusado"));
                              if (acusado == null){
                                      acusado = new Acusado();
                                      log.info("El acusado vino null");
                              }
                      }
                      
                      boolean bol = entityManager.contains(acusado);
              }
              
      
              public void verPaginaRetorno()
              {
                              if (returnTo != null)
                                      from = returnTo;
              }
      
              public void cleanVar(String varName){
                      org.jboss.seam.contexts.Contexts.getConversationContext().remove(varName);
              }
              
      
              public String getReturnTo() {
                      return returnTo;
              }
      
      
              public void setReturnTo(String returnTo) {
                      this.returnTo = returnTo;
              }
      
      
              public String getFrom() {
                      return from;
              }
      
      
              public void setFrom(String from) {
                      this.from = from;
              }
      
      }
      



      the entity detail page:



      <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                                   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <ui:composition xmlns="http://www.w3.org/1999/xhtml"
              xmlns:s="http://jboss.com/products/seam/taglib"
              xmlns:ui="http://java.sun.com/jsf/facelets"
              xmlns:f="http://java.sun.com/jsf/core"
              xmlns:h="http://java.sun.com/jsf/html"
              xmlns:rich="http://richfaces.org/rich" template="layout/template.xhtml">
      
              <ui:define name="body">
      
                      <h:messages globalOnly="true" styleClass="message" />
      
                      <h:form id="expedienteForm">
      
                              <rich:panel>
                                      <f:facet name="header">expediente</f:facet>
      
                                      <s:decorate id="nameDecoration" template="layout/edit.xhtml">
                                              <ui:define name="label">Numero de expediente</ui:define>
                                              <h:inputText id="nro" required="true"
                                                      value="#{expedienteHome.instance.nroExpediente}" />
                                      </s:decorate>
      
                                      <div style="clear: both" />
      
                              </rich:panel>
      
                              <div class="actionButtons"><h:commandButton id="save"
                                      value="Salvar" action="#{expedienteHome.persist}"
                                      rendered="#{!expedienteHome.managed}" /> <h:commandButton
                                      id="update" value="Actualizar" action="#{expedienteHome.update}"
                                      rendered="#{expedienteHome.managed}" /> <h:commandButton
                                      id="delete" value="Eliminar" action="#{expedienteHome.remove}"
                                      immediate="true" rendered="#{expedienteHome.managed}" /> <s:button
                                      propagation="end" id="expedienteDone" value="Terminar"
                                      view="/expedienteList.xhtml" /></div>
      
                              <rich:panel>
                                      <rich:tabPanel id="expCollections">
                                              
                                              <rich:tab id="acusadosTab" label="Acusados">
      
                                                      <!--                                                 <h:messages globalOnly="true" styleClass="message" />  -->
      
                                                      <rich:panel>
                                                              <f:facet name="header">Listado de acusados para el expediente actual</f:facet>
      
                                                              <div class="results"><h:outputText
                                                                      value="No existen acusados asociados a este expediente aun"
                                                                      rendered="#{empty expedienteHome.getAcusados()}" /> <h:dataTable
                                                                      id="acusadoList" var="acusado" value="#{listaAcusados}"
                                                                      rendered="#{not empty listaAcusados}" cellpadding="2"
                                                                      rowClasses="graybg,whitebg">
                                                                      <h:column>
                                                                              <f:facet name="header">CI</f:facet>
                          #{acusado.ci}
                      </h:column>
      
                                                                      <h:column>
                                                                              <f:facet name="header">Nombre</f:facet>
                                                                              <s:link id="nombreLink" value="#{acusado.nombre}"
                                                                                      view="/registerAcusado.xhtml" propagation="join">
                                                                                      <f:param name="returnTo" value="/expediente.xhtml" />
                                                                          </s:link>
                                                                      </h:column>
      
                                                                      <h:column>
                                                                              <f:facet name="header">Direccion</f:facet>
                          #{acusado.direccionParticular}
                      </h:column>
      
                                                                      <h:column>
                                                                              <f:facet name="header">Desc Fisica</f:facet>
                          #{acusado.descripcionFisica}
                                      </h:column>
      
                                                              </h:dataTable></div>
      
                                                      </rich:panel>
      
                                                      <div class="actionButtons"><s:button id="acusadoDone"
                                                              value="Create acusado" view="/registerAcusado.xhtml">
                                                              <f:param name="returnTo" value="/expediente.xhtml" />
                                                      </s:button></div>
      
                                              </rich:tab>
                                      </rich:tabPanel>
                              </rich:panel>
                      </h:form>
      
              </ui:define>
      
      </ui:composition>
      
      


        • 1. Re: Lazy loading problem
          tony.herstell1

          private EntityManager entityManager;


          This is not in extended mode... should it be?

          • 2. Re: Lazy loading problem
            maykell.mflores.uci.cu

            Hi, yes i am using am extended managed persistence context because i am using a seam managed persistence context that is injected via the @In annotation.


            I can´t figured out what can be the problem.
            Any idea or suggestion will be very appreciated...

            • 3. Re: Lazy loading problem
              sanghakanwar

              Try changing this -



                 @ManyToOne (fetch = FetchType.LAZY)
                      @JoinColumn(name="Expediente_ID",nullable = false)
                      public Expediente getExpediente() {
                              return expediente;
                      }
              
              
              
              
                
              @ManyToOne (fetch = FetchType.EAGER)
                      @JoinColumn(name="Expediente_ID",nullable = false)
                      public Expediente getExpediente() {
                              return expediente;
                      }



              • 4. Re: Lazy loading problem
                gjeudy

                You have to understand that SMPC managed entities are cached in 1st level cache for the duration of the conversation so that

                getAcusados

                doesn't refresh unless you load your Expediente in a new conversation (SMPC) or explicitely refresh it
                EntityManager.refresh(expediente)

                .


                In your case you can either:



                • End the conversation whenever a new entity is added.




                • I would rather suggest add a method enforcing bidirectional wiring. Create a new Expediente.addAcusado() method and call it when you persist your new Acusados. This will ensure your in-memory Expediente gets updated without having to reload Expediente from the database.



                public void addAcusado(Acusado acusado) {
                                this.acusados.add(acusado);
                                acusado.setExpediente(this);
                        }
                



                • 5. Re: Lazy loading problem
                  maykell.mflores.uci.cu

                  Hi Guillaume, your advise works great, now it generate several question to me:




                  Guillaume Jeudy wrote on Sep 08, 2008 16:10:


                  You have to understand that SMPC managed entities are cached in 1st level cache for the duration of the conversation so that
                  getAcusados

                  doesn't refresh unless you load your Expediente in a new conversation (SMPC) or explicitely refresh it
                  EntityManager.refresh(expediente)

                  .

                  I do not understand this very well, because i make a flush() after i invoke the persist method when a new Acusado object is registered, beside that in order to view the list of Acusados from an Expediente instance, i end the conversation where i persist the Acusado and open a new one when i pick up an Expediente from the list page, the Expediente is loaded by its id making a query, ¿why i have to refresh it still? 


                  In your case you can either:



                    End the conversation whenever a new entity is added.

                  I end the conversation after several entities are added, and only after that i try to get the list of Acusados of a given Expediente by invoking the lazy method getAcusados()



                    I would rather suggest add a method enforcing bidirectional wiring. Create a new Expediente.addAcusado() method and call it when you persist your new Acusados. This will ensure your in-memory Expediente gets updated without having to reload Expediente from the database.


                  public void addAcusado(Acusado acusado) {
                                  this.acusados.add(acusado);
                                  acusado.setExpediente(this);
                          }

                  I considered that idea but i rejected it because of my feeling of that could lead to a potential lack of memory problem when the number of Acusado objects added to the list grows too much.





                  Click HELP for text formatting instructions. Then edit this text and check the preview.

                  • 6. Re: Lazy loading problem
                    maykell.mflores.uci.cu

                    Hi Guillaume, Sorry for the rating i gived to your answer, it was a bad click trying to rate 5 starts, your answer is very good and help ed me too much, i thank you very much.