我试着在这里提问 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用于描述。
我正在努力学习并花费大量时间试图找出这一点,但没有任何作用。这不是那么困难。我只是不明白。
提前感谢您的帮助。
如果可能的话,如果有人可以在某个地方发布如何处理类似问题的完整示例,我将非常感激。
答案 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映射,但它是另一个问题的主题。