问题
Here is my dilemma, I know in JSF the accessor method will get call mutilple times, therefore I know not to put expensive business logic (like DB access) in accessor method. What if I absolutely have to put business logic into my accessor. What should I do in this case? Below are a high level layout of my dilemma. (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);
}
}
As you can see, the inner
dataTable take in the item
of the outer
dataTable to generate its List. Is there a way for somehow stop handleReplies()
to be called multiple times, since this accessor method access DB.
回答1:
How about using a HashMap
to create a view-scoped cache?
Something like:
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);
}
This way, your view-scoped bean store previous request results, and returns them if the request has already been done. If it hasn't, the request is made. In the end, no duplicate request!
回答2:
You can also just let JPA do the lazy loading and caching job (with a proper second level cache).
Assuming that your Comment
entity look like this
@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;
// ...
}
You could just use #{comment.children}
to (lazily) get the children in a <h:dataTable>
.
来源:https://stackoverflow.com/questions/6022337/jsf-absolutely-need-to-put-expensive-business-logic-inside-accessor-method-how