<f:viewParam> javax.persistence.NoResultException: 未找到要查询的实体

<f:viewParam> javax.persistence.NoResultException: No entity found for query

我有一个网格,用户可以在其中查看他的记录,当他单击一条记录时,它会链接到另一个页面,以便他可以编辑或删除它。

该页面中的记录显示正确,并且它有一个按钮来更新记录(如果进行了任何更改并让用户返回网格)。

我正在使用 Java 1.8 和 Primefaces,在 Netbeans 8.0.2 和 wildfy 8.2 上,我的 OS 是 UBUNTU。

当我尝试更改某些内容时,页面什么也没做,我在 wildfly 日志中有这条记录

15:11:16,369 ERROR [org.jboss.as.ejb3] (default task-19) javax.ejb.EJBTransactionRolledbackException: No entity found for query 15:11:16,371 ERROR [org.jboss.as.ejb3.invocation] (default task-19) JBAS014134: EJB Invocation failed on component GastoDAOImpl for method public abstract dominio.Gasto persistencia.GastoDAO.getGastoporID(int): javax.ejb.EJBTransactionRolledbackException: No entity found for query

Caused by: javax.persistence.NoResultException: No entity found for query

15:11:16,405 ERROR [org.jboss.as.ejb3.invocation] (default task-19) JBAS014134: EJB Invocation failed on component GastoControladorImpl for method public abstract dominio.Gasto controladores.GastoControlador.obtenerGastoporID(int): javax.ejb.EJBTransactionRolledbackException: No entity found for query

15:11:16,439 SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (default task-19) javax.faces.component.UpdateModelException: javax.el.ELException: /editargastos.xhtml @10,64 value="#{gastoBean.idGasto}": javax.ejb.EJBTransactionRolledbackException: No entity found for query

奇怪的是,如果我 运行 程序处于调试模式,则完全没有问题,系统按预期工作(数据被正确修改,用户刚刚返回到主网格.

我的代码:

1) 这是显示将要修改的项目的记录的页面 它在调试模式或正常模式下显示正确的记录

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:p="http://primefaces.org/ui"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
    <h:head>
        <f:metadata>
            <f:viewParam name="id_gasto" value="#{gastoBean.idGasto}"/>
        </f:metadata>

        <title>Gaston editar un gasto</title>
    </h:head>
    <h:body>
        <div id="header">
            <ui:insert name="header">
                <ui:include src="defaultHeader.xhtml" />
            </ui:insert>  
        </div>

        <h2>Editar un gasto  Propietario: #{loginBean.usuario.apellido}</h2>
        <h3>Familia: #{loginBean.usuario.familia.nombre}</h3>

        <h:form>
            <h:messages></h:messages>
            <p:panelGrid columns="2">
                <h:outputText value=" Fecha de pago" />     
                <p:calendar value="#{gastoBean.gasto.fecha_registro}" required="true"/>
                <h:outputText value=" Moneda" />     
                <h:selectOneMenu id="moneda" value="#{gastoBean.gasto.moneda}" >
                    <f:selectItems value="#{gastoBean.monedas}"></f:selectItems>
                </h:selectOneMenu>
                <h:outputText value="Monto" />   
                <h:inputText value="#{gastoBean.gasto.monto}" required="true"/>
                <h:outputText value=" Descripcion" />     
                <h:inputText value="#{gastoBean.gasto.descripcion}" required="true"/>
                <h:outputText value=" Clasificacion" />     
                <h:inputText value="#{gastoBean.gasto.clasificacion}" required="true"/>

            </p:panelGrid>
            <br></br>

            <p:commandButton action="#{gastoBean.modificarGasto()}" value="Modificar gasto" />
            <p:commandButton action="#{gastoBean.eliminarGasto(id_gasto)}" value="Eliminar gasto" />

            <br></br>
            <h:outputText value="#{gastoBean.mensaje}"  />
            <br></br><br></br>
            <hr></hr>
            <small>Todos los campos son obligatorios</small>
        </h:form>
    </h:body>
</html>

2) Backing bean:这是上一页中修改项调用的 bean,当系统 运行s 处于调试模式时,我可以看到每一行都按预期工作,完成后数据库已更新,用户已发送到网格。

但是...如果我 运行 没有调试选项的程序它根本无法工作,既不修改数据库,也不显示用户重定向,也不显示异常。

public void modificarGasto() {
    try {
        controlador.modificarGasto(gasto);
        Familia f = this.autenticado.getUsuario().getFamilia();
        this.listaGastos = controlador.obtenerGastosFamiliaporID(f.getId_familia());
        ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();

        ec.redirect("listadog.xhtml");
    } catch (Exception e) {
        this.mensaje = "ERROR: No se pudo guardar el registro";
    }
}

更新:我只是修改了附加到按钮的方法,只是为了给出一条消息,但在 "normal mode" 中都不起作用我开始认为这实际上是 Primefaces 中的一个错误:(

好吧,我仍然不知道为什么当我调试它时它会工作并且在 "normal mode dont" 但经过更多小时或解决它后我找到了另一种方法来做我想做的事情所以我只是分享信息以防其他人可能会用到它。

我删除了参数的代码

相反,我在网格中添加了一种将项目保存在会话 bean 中的方法,因此当 edit.xhtml 呈现时 IT 可以处理它。

无需进一步更改

javax.persistence.NoResultException: No entity found for query

当您使用 JPA Query#getSingleResult() 并且查询实际上没有 return 任何结果时,将抛出此特定异常。您应该阅读异常的堆栈跟踪,以确定负责调用此方法的人,并了解当时调用此方法的确切原因。

根据目前提供的稀疏信息(实际上,完整的堆栈跟踪几乎可以解释和回答所有问题;请记住 post 在任何有关您无法解决的异常的问题中完整地查看堆栈跟踪' t 解释),我只能做出有根据的猜测,你将 <f:viewParam> 绑定到一个请求范围的 bean 而不是一个视图范围的 bean,并且它以某种方式触发一些代码来转换作为请求参数提供的 ID到使用带有 getSingleResult() 的 JPA 查询的实际实体。当您在该视图中提交表单时,请求作用域 bean 将被重新创建,实体将为 null,<f:viewParam> 将再次 运行,但初始请求参数不再存在。

如您尝试回答的那样,将会话范围的 bean 滥用于视图范围的数据是错误的解决方案。为此,您至少需要一个视图范围的 bean。而且,根据问题的真正根本原因,您可能需要进行更多更改。可以在下面的 "See also" 链接中找到提示:

另见

  • Creating master-detail pages for entities, how to link them and which bean scope to choose
  • What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
  • Process f:viewParam only on page load
  • <f:viewParam lost after second ajax call