value =“#{nnController.nnDescr.descr}”:目标无法访问,'null'返回null

时间:2015-02-20 13:58:52

标签: jsf jsf-2

我试着在这里提问 https://stackoverflow.com/questions/28493517/jsf-primefaces-editing-object-composed-of-2-tables但我担心没有正确地询问,这是我尝试的方式,尽可能简单。

我有两张桌子:

nn:       id, name 
nn_descr: id, long_description

nn_descr.id和nn.id之间存在外键约束。

通常,与nn_descr表相比,一个表包含可以通过db引擎快速搜索和管理的数据。

现在我想管理这些数据,而不是像所有CRUD创建者那样。我希望通过JSF表单上的一个提交在我的表中创建2个相关记录,该表单包含分别引用到nn.name和descr.long_description的文本框和文本区域。

如果没有JPA,我会将记录插入第一个表,读取标识值并使用我已读过的标识值将数据插入第二个表。

使用JPA,我应该以某种方式告诉该引擎神奇地保留数据。 这就是我不知道如何做到这一点。无论我读到什么,都是指简单的CRUD,只需通过我的Netbeans即可轻松生成。

我必须承认我迷失了这个JPA,外墙和所有产生的东西,但我试图通过简单的应用来学习这个

我设法让两个表中的记录都可更新。但是当我尝试插入数据时,我得到了:

/nn/Create.xhtml @21,81 value="#{nnController.nnDescr.descr}": Target Unreachable, 'null' returned null

我一定做错了什么,但我不知道在哪里可以找到答案,教程,书籍,比那个表中有一个平面表和CRUD的简单示例稍微深一些。

这是我的JSF(尽可能基本):

<?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:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">

  <ui:composition template="/template.xhtml">
    <ui:define name="title">
      <h:outputText value="#{boundle.CreateNnTitle}"></h:outputText>
    </ui:define>
    <ui:define name="body">
      <h:panelGroup id="messagePanel" layout="block">
        <h:messages errorStyle="color: red" infoStyle="color: green" layout="table"/>
      </h:panelGroup>
      <h:form>
        <h:panelGrid columns="2">
          <h:outputLabel value="#{boundle.CreateNnLabel_nnName}" for="nnName" />
          <h:inputText id="nnName" value="#{nnController.selected.nnName}" title="#{boundle.CreateNnTitle_nnName}" />
          <h:outputLabel value="#{boundle.CreateNnLabel_nnDescr}" for="nnDescr" />
          <h:inputTextarea id="nnDescr" value="#{nnController.selected.nnDescr.descr}" />
        </h:panelGrid>
        <br />
        <h:commandLink action="#{nnController.create}" value="#{boundle.CreateNnSaveLink}" />
        <br />
        <br />
        <h:commandLink action="#{nnController.prepareList}" value="#{boundle.CreateNnShowAllLink}" immediate="true"/>
        <br />
        <br />
        <h:link outcome="/index" value="#{boundle.CreateNnIndexLink}"/>
      </h:form>
    </ui:define>
  </ui:composition>

和控制器

package app;

import app.util.JsfUtil;
import app.util.PaginationHelper;

import java.io.Serializable;
import java.util.ResourceBundle;
import javax.ejb.EJB;
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;

@Named("nnController")
@SessionScoped
public class NnController implements Serializable {

  private Nn current;
  private NnDescr nnDescr;

  private DataModel items = null;
  @EJB
  private app.NnFacade ejbFacade;


  private PaginationHelper pagination;
  private int selectedItemIndex;

  public NnController() {
  }

  public Nn getSelected() {
    if (current == null) {
      current = new Nn();

      selectedItemIndex = -1;
    }
    return current;
  }

  private NnFacade getFacade() {
    return ejbFacade;
  }

  public PaginationHelper getPagination() {
    if (pagination == null) {
      pagination = new PaginationHelper(10) {

        @Override
        public int getItemsCount() {
          return getFacade().count();
        }

        @Override
        public DataModel createPageDataModel() {
          return new ListDataModel(getFacade().findRange(new int[]{getPageFirstItem(), getPageFirstItem() + getPageSize()}));
        }
      };
    }
    return pagination;
  }

  public String prepareList() {
    recreateModel();
    return "List";
  }

  public String prepareView() {
    current = (Nn) getItems().getRowData();
    selectedItemIndex = pagination.getPageFirstItem() + getItems().getRowIndex();
    return "View";
  }

  public String prepareCreate() {
    current = new Nn();


    selectedItemIndex = -1;
    return "Create";
  }

  public String create() {
    try {
      getFacade().create(current);
      JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Boundle").getString("NnCreated"));
      return prepareCreate();
    } catch (Exception e) {
      JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Boundle").getString("PersistenceErrorOccured"));
      return null;
    }
  }

  public String prepareEdit() {
    current = (Nn) getItems().getRowData();
    selectedItemIndex = pagination.getPageFirstItem() + getItems().getRowIndex();
    return "Edit";
  }

  public String update() {
    try {
      getFacade().edit(current);
      JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Boundle").getString("NnUpdated"));
      return "View";
    } catch (Exception e) {
      JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Boundle").getString("PersistenceErrorOccured"));
      return null;
    }
  }

  public String destroy() {
    current = (Nn) getItems().getRowData();
    selectedItemIndex = pagination.getPageFirstItem() + getItems().getRowIndex();
    performDestroy();
    recreatePagination();
    recreateModel();
    return "List";
  }

  public String destroyAndView() {
    performDestroy();
    recreateModel();
    updateCurrentItem();
    if (selectedItemIndex >= 0) {
      return "View";
    } else {
      // all items were removed - go back to list
      recreateModel();
      return "List";
    }
  }

  private void performDestroy() {
    try {
      getFacade().remove(current);
      JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Boundle").getString("NnDeleted"));
    } catch (Exception e) {
      JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Boundle").getString("PersistenceErrorOccured"));
    }
  }

  private void updateCurrentItem() {
    int count = getFacade().count();
    if (selectedItemIndex >= count) {
      // selected index cannot be bigger than number of items:
      selectedItemIndex = count - 1;
      // go to previous page if last page disappeared:
      if (pagination.getPageFirstItem() >= count) {
        pagination.previousPage();
      }
    }
    if (selectedItemIndex >= 0) {
      current = getFacade().findRange(new int[]{selectedItemIndex, selectedItemIndex + 1}).get(0);
    }
  }

  public DataModel getItems() {
    if (items == null) {
      items = getPagination().createPageDataModel();
    }
    return items;
  }

  private void recreateModel() {
    items = null;
  }

  private void recreatePagination() {
    pagination = null;
  }

  public String next() {
    getPagination().nextPage();
    recreateModel();
    return "List";
  }

  public String previous() {
    getPagination().previousPage();
    recreateModel();
    return "List";
  }

  public SelectItem[] getItemsAvailableSelectMany() {
    return JsfUtil.getSelectItems(ejbFacade.findAll(), false);
  }

  public SelectItem[] getItemsAvailableSelectOne() {
    return JsfUtil.getSelectItems(ejbFacade.findAll(), true);
  }

  public Nn getNn(java.lang.Integer id) {
    return ejbFacade.find(id);
  }

  public NnDescr getNnDescr() {
    return nnDescr;
  }

  public void setNnDescr(NnDescr nnDescr) {
    this.nnDescr = nnDescr;
  }




  @FacesConverter(forClass = Nn.class)
  public static class NnControllerConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
      if (value == null || value.length() == 0) {
        return null;
      }
      NnController controller = (NnController) facesContext.getApplication().getELResolver().
              getValue(facesContext.getELContext(), null, "nnController");
      return controller.getNn(getKey(value));
    }

    java.lang.Integer getKey(String value) {
      java.lang.Integer key;
      key = Integer.valueOf(value);
      return key;
    }

    String getStringKey(java.lang.Integer value) {
      StringBuilder sb = new StringBuilder();
      sb.append(value);
      return sb.toString();
    }

    @Override
    public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
      if (object == null) {
        return null;
      }
      if (object instanceof Nn) {
        Nn o = (Nn) object;
        return getStringKey(o.getId());
      } else {
        throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + Nn.class.getName());
      }
    }

  }
}

Nn.java

package app;

import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.validation.constraints.Size;


@Entity
@Table(name = "nn")
@NamedQueries({
  @NamedQuery(name = "Nn.findAll", query = "SELECT n FROM Nn n"),
  @NamedQuery(name = "Nn.findById", query = "SELECT n FROM Nn n WHERE n.id = :id"),
  @NamedQuery(name = "Nn.findByNnName", query = "SELECT n FROM Nn n WHERE n.nnName = :nnName")})
public class Nn implements Serializable {
  private static final long serialVersionUID = 1L;
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Basic(optional = false)
  @Column(name = "id")
  private Integer id;
  @Size(max = 50)
  @Column(name = "nn_name")
  private String nnName;
  @OneToOne(cascade = CascadeType.ALL, mappedBy = "nn")
  private NnDescr nnDescr;

  public Nn() {
  }

  public Nn(Integer id) {
    this.id = id;
  }

  public Integer getId() {
    return id;
  }

  public void setId(Integer id) {
    this.id = id;
  }

  public String getNnName() {
    return nnName;
  }

  public void setNnName(String nnName) {
    this.nnName = nnName;
  }

  public NnDescr getNnDescr() {
    return nnDescr;
  }

  public void setNnDescr(NnDescr nnDescr) {
    this.nnDescr = nnDescr;
  }

  @Override
  public int hashCode() {
    int hash = 0;
    hash += (id != null ? id.hashCode() : 0);
    return hash;
  }

  @Override
  public boolean equals(Object object) {
    // TODO: Warning - this method won't work in the case the id fields are not set
    if (!(object instanceof Nn)) {
      return false;
    }
    Nn other = (Nn) object;
    if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
      return false;
    }
    return true;
  }

  @Override
  public String toString() {
    return "app.util.Nn[ id=" + id + " ]";
  }

}

如您所见,生成了数据。我刚刚修改了生成的JSF,以便让textarea用于描述。

我正在努力学习并花费大量时间试图找出这一点,但没有任何作用。这不是那么困难。我只是不明白。

提前感谢您的帮助。

如果可能的话,如果有人可以在某个地方发布如何处理类似问题的完整示例,我将非常感激。

2 个答案:

答案 0 :(得分:0)

  

value =&#34;#{nnController.nnDescr.descr}&#34;:目标无法访问,&#39; null&#39;返回null

这意味着#{nnController}#{nnController.nnDescr}返回null,因此EL无法在其上调用descr的设置者,以便更新具有提交的输入值的模型。

鉴于对#{nnController}的其他引用工作正常,它将#{nnController.nnDescr}返回null。实际上,你没有在你的豆子里准备它。

相应修复:

@PostConstruct
public void init() {
    nnDescr = new NnDescr();
}

无关具体问题,该bean应该是视图范围,而不是会话范围。另请参阅How to choose the right bean scope?

那就是说,你最好从一本真实的书开始,以便根据真实的指令,解释,可行的片段/例子来学习JSF,而不是在没有任何基础知识/经验的情况下无知地凝视自动生成的代码。您可以在our JSF wiki page找到链接。

答案 1 :(得分:0)

谢谢你,@ PostConstruct是我的问题的正确答案。 另一个问题是如何正确地进行JPA映射,但它是另一个问题的主题。