在提交JSF页面时记录了意外的JPA SELECT语句

时间:2015-04-26 23:23:37

标签: jsf jpa

我将Glassfish Server 4.1与捆绑的JSF一起使用。我已经启用了JPA FINE登录" persistence.xml"。

我有这个Facelets页面:

<p:dataTable var="customer" value="#{customerService.customers}">
</p:dataTable>
<h:form>
    <h:commandButton value="Test"/>
</h:form>

(请注意,确实存在以下情况:我没有将操作与按钮相关联,或者在表格中添加了列,如果我这样做了,那我的行为就是描述并没有改变。还记得默认render行为是@none。)

这个无状态EJB(使用@Named以便页面可以直接引用它):

@Stateless
@Named
public class CustomerService {

    @PersistenceContext
    private EntityManager em;

    public List<Customer> getCustomers() {
        return em.createNamedQuery("Customer.findAll", Customer.class).getResultList();
    }
    ...

加载页面时,日志中会显示以下消息:

Fine:   SELECT ID, CUSTOMERNAME, EMAIL, PAID, QUANTITY, TYPE FROM CUSTOMER

到目前为止一切顺利。当我单击按钮时,它会出现在日志中:

Fine:   SELECT ID, CUSTOMERNAME, EMAIL, PAID, QUANTITY, TYPE FROM CUSTOMER
Fine:   SELECT ID, CUSTOMERNAME, EMAIL, PAID, QUANTITY, TYPE FROM CUSTOMER
... Same message appears five more times ...

Customers表为空。

有人可以复制或解释这种行为吗?一个用于页面加载的SELECT是有意义的,但是表单提交的七个SELECTS令人困惑。

更新

如果我将EJB移动到ViewScoped JSF backing-bean并更新Facelets页面以使用它,行为将保持不变:

@ManagedBean // javax.faces.bean.
@ViewScoped
public class BackingBean {
    @EJB
    private CustomerService cs;
    public List<Customer> getCustomers() {
        return cs.getCustomers();
    } 
}

2 个答案:

答案 0 :(得分:0)

我认为问题出在你在bean中使用的范围内,让我从其他question引用它:

  

如果是@Named的CDI,则默认为@Dependent,如Weld documentation中所述:   最后,CDI具有所谓的依赖伪范围。这是没有显式声明范围类型的bean的默认范围。效果是在每个单独的EL表达式上新创建了bean实例。因此,想象一个登录表单,其中两个输入字段引用bean属性,而一个命令按钮引用bean操作,因此总共有三个EL表达式,那么实际上将创建三个实例。

现在,我们如何解决它?也许你应该根据你的要求Check out this documentation about Scopes and context in JSF为你的bean尝试另一个范围。

答案 1 :(得分:0)

正如Tiny在我的问题评论中解释的那样,额外的日志记录正在发生,因为我将业务逻辑放在Facelets页面使用的getter方法中。通常不赞成将业务逻辑放在Facelets页面使用的访问器(getter setter)方法中,因为这些方法由JSF框架使用,并且您几乎无法控制它们何时以及多久经常使用被称为。

在这种情况下,问题可以解决问题&#34;通过在JSF视图范围的backing-bean的@PostConstruct方法中初始化客户:

@PostConstruct
public void init() {
    customers = customerService.getCustomers();
}
public List<Customer> getCustomers() {
    return customers;
}

这是一个更传统的设置,但我试图在没有JSF支持bean的情况下使用。

如果有人可以解释为什么 JSF框架正在调用方法次,这似乎是随意的,我肯定会将答案标记为正确,但与此同时我是对此感到满意。

<强>更新

对确切呼叫数量的解释,七,可能与此答案相似,Why is the getter called so many times by the rendered attribute?

  

在渲染响应阶段,getter调用全部由rendered="#{selector.profilePage == 'some'}"完成。在评估false时   第一次,在UIComponent#encodeAll(),然后没有更多的电话   将会完成。当它评估true时,它将被重新评估    按以下顺序多次...