这是我的困境,我知道在JSF中访问器方法会多次调用,因此我知道不要在访问器方法中放置昂贵的业务逻辑(如DB访问)。如果我必须将业务逻辑放入我的访问器中该怎么办?在这种情况下我该怎么办?以下是我的困境的高层次布局。 (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);
}
}
如您所见,inner
dataTable接受item
dataTable的outer
生成其List。有没有办法以某种方式停止handleReplies()
被多次调用,因为这个访问器方法访问DB。
答案 0 :(得分:2)
如何使用HashMap
创建视图范围的缓存?
类似的东西:
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);
}
这样,视图范围的bean存储先前的请求结果,并在请求已经完成时返回它们。如果没有,则发出请求。最后,没有重复请求!
答案 1 :(得分:2)
您也可以让JPA执行延迟加载和缓存作业(使用适当的二级缓存)。
假设您的Comment
实体看起来像这样
@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;
// ...
}
您可以使用#{comment.children}
(懒惰地)让孩子们进入<h:dataTable>
。