You can find the full source code for this website in the Seam package in the directory /examples/wiki. It is licensed under the LGPL.
| Online: | 13 Members of 8195 |
| Forum: Seam Users |
01. Sep 2008, 22:29 CET | Link |
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>
private EntityManager entityManager;
This is not in extended mode... should it be?
But I being poor have only my dreams. I have spread my dreams under your feet. Tread softly because you tread on my dreams...
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...
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; }You have to understand that SMPC managed entities are cached in 1st level cache for the duration of the conversation so that
doesn't refresh unless you load your Expediente in a new conversation (SMPC) or explicitely refresh it .In your case you can either:
public void addAcusado(Acusado acusado) { this.acusados.add(acusado); acusado.setExpediente(this); }Hi Guillaume, your advise works great, now it generate several question to me:
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:
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 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.
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.