JSF: Es absolutamente necesario poner una costosa lógica empresarial dentro del método de acceso. Cómo evitar llamar a este costoso tiempo de múltiplos de BL

Aquí está mi dilema, sé que en JSF el método de acceso recibirá llamadas múltiples veces, por lo tanto, sé que no debo poner lógica comercial costosa (como el acceso a la base de datos) en el método de acceso. ¿Qué pasa si absolutamente tengo que poner lógica de negocios en mi descriptor de acceso? ¿Qué debo hacer en este caso? A continuación se muestra un diseño de alto nivel de mi dilema. (Mojarra 2.1, GF 3.1)

<h:dataTable value="#{myBean.comments}" var="item1">
    <h:column>
          #{item1.name} says: #{item1.comment}
          <h:dataTable value="#{myBean.handleReplies(item1)}" var="item2">
               <h:column>
                   #{item2.name} replies: #{item2.comment}
               </h:column>
          </h:dataTable>    
    </h:column>
</h:dataTable>    

@ManagedBean
@ViewScoped
public void myBean(){
    private List<Comment> comments;

    @EJB
    private MyEJB myEJB;

    @PostConstruct
    public void init(){
        comments = myEJB.getAllComments();
    }

    //getters and setters for List<Comment> comments

    public List<Comment> handleReplies(Comment comment){
         //Return a List of replies of the comment
         return myEJB.getRepliesFromComment(comment); 
    }
}

Como se puede ver, el inner dataTable toma en el item de los outer dataTable para generar su List. ¿Hay alguna manera de detener de alguna manera? handleReplies() para ser llamado varias veces, ya que este método de acceso accede a la base de datos.

preguntado el 16 de mayo de 11 a las 19:05

¿No es una opción tener un #{item1.comments} donde la carga diferida solo es manejada por JPA? -

@BalusC: ¿Puedes explicar un poco más, BalusC? No estoy seguro de entender a qué te refieres.

Naturalmente esperaría eso Comment es una entidad JPA que tiene un @OneToMany List<Comment> propiedad que es recuperada perezosamente por FetchType.LAZY. ¿O tenías razones para no hacerlo? -

@BalusC: Comment es de hecho una entidad JPA, que tiene @OneToMany List , pero no tengo FetchType.LAZY lo. Que hace FetchType.LAZY ¿BalusC? -

Permitirá que JPA cargue perezosamente (y eventualmente almacene en caché) los hijos una vez que la lista devuelta se haya iterado por primera vez. No se cargarán directamente cuando obtenga solo los padres. Pero como ya lo ha hecho ... ¿Por qué no usa #{item1.comments} en lugar de #{myBean.handleReplies(item1)}? -

2 Respuestas

¿Qué tal usar un HashMap para crear una caché con alcance de vista?

Algo como:

private Map<Comment, List<Comment>> replies = new HashMap<Comment, List<Comment>>();

public List<Comment> handleReplies(Comment comment){
    if (!replies.containsKey(comment)) {
        replies.put(comment, myEJB.getRepliesFromComment(comment));
    }

    return replies.get(comment);
}

De esta manera, su bean de ámbito de vista almacena los resultados de la solicitud anterior y los devuelve si la solicitud ya se ha realizado. Si no es así, se realiza la solicitud. ¡Al final, ninguna solicitud duplicada!

contestado el 16 de mayo de 11 a las 23:05

En realidad, esta es una gran idea. Gracias. - Thang Pham

También puede dejar que JPA haga el trabajo de carga diferida y almacenamiento en caché (con una caché de segundo nivel adecuada).

Asumiendo que tu Comment entidad se ve así

@Entity
@NamedQuery(name="Comment.list", query="SELECT c FROM Comment c WHERE c.parent IS NULL")
public class Comment implements Serializable {

    @ManyToOne(optional=false)
    private Comment parent;

    @OneToMany(mappedBy="parent", fetch=LAZY, cascade=ALL);
    private List<Comment> children;

    // ...
}

Podrías usar #{comment.children} para (perezosamente) poner a los niños en un <h:dataTable>.

contestado el 17 de mayo de 11 a las 00:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.