【发布时间】:2014-08-12 13:25:57
【问题描述】:
我尝试在 PrimeFaces 4.0 中以动态模式与持久性 API 一起使用 p:tree。 我有 @Entity 类(Nomen),它已经有引用自身的元素。我尝试了这两种变体:在那个非常 Nomen 类接口 TreeNode 中实现并使其成为 DefaultTreeNode 的子类。最后一个变体扩展了 DefaultTreeNode。行为是一样的。
@Entity
@Table(name = "Nomen")
public class Nomen extends DefaultTreeNode implements Serializable {
@Id
private Integer id;
...
@Column(name = "Name")
private String name;
...
@JoinColumn(name = "Self_Id", referencedColumnName = "Id")
@ManyToOne
private Nomen parent;
@OneToMany(mappedBy = "parent", fetch=FetchType.EAGER)
private List<Nomen> nomenCollection;
...
public Nomen() {
super();
}
...
@Override
public String getType() {
if (nomenCollection == null) return "NomenLeaf";
return "NomenGroup";
}
@Override
public Nomen getData() {
Logger.getLogger(this.getClass().getName()).log(Level.INFO, "getData for {0}", new Object[] {this});
return this;
}
@Override
public Nomen getParent() {
return this.parent;
}
@Override
public void setParent(TreeNode tn) {
if (!(tn instanceof Nomen)) {
return;
}
try {
parent.removeChild(this);
}
catch (NullPointerException e) { }// Nothing to do
if (tn != null) {
((Nomen)tn).addChild(this);
}
parent = (Nomen)tn;
}
@Override
public int getChildCount() {
if (nomenCollection == null) return 0;
return nomenCollection.size();
}
@Override
public boolean isLeaf() {
return nomenCollection == null;
}
@Override
public String getRowKey() {
Logger.getLogger(this.getClass().getName()).log(Level.INFO, "getRowKey: this: {0} id: {1}", new Object[] {this, Integer.toString(getId())} );
return Integer.toString(getId());
}
@Override
public List<TreeNode> getChildren() {
// return new ArrayList<TreeNode> (nomenCollection);
// return (List<TreeNode>)(List<? extends TreeNode>)nomenCollection;
ArrayList<TreeNode> r = new ArrayList<> ();
for (Nomen n : nomenCollection) {
r.add(n);
}
Logger.getLogger(this.getClass().getName()).log(Level.INFO, "getChildren for {0}: List: {1} ", new Object[] {this, r});
return r;
}
public List<Nomen> getNomenCollection() {
return nomenCollection;
}
public void setNomenCollection (List<Nomen> n) {
nomenCollection = n;
}
}
XHTML 文件非常简单,就像 PrimeFaces 示例一样:
<h:form id="myform">
<p:tree id="ntree" value="#{nomenPfCtl.root}" var="item" selectionMode="single" selection="#{nomenPfCtl.selected}" datakey="id" dynamic="true">
<p:treeNode type="NomenGroup" expandedIcon="ui-icon-folder-open" collapsedIcon="ui-icon-folder-collapsed">
<h:outputText value="#{item}"/>
</p:treeNode>
<p:treeNode type="NomenLeaf" expandedIcon="ui-icon-document" collapsedIcon="ui-icon-document">
<h:outputText value="#{item}"/>
</p:treeNode>
</p:tree>
</h:form>
p:tree 奇怪的无法解释的行为是它通常(使用 Nomen.toString)只呈现根节点的第二个(最后一个)子节点(id=2)。它呈现整个树形结构,可以用图标进一步扩展,但标签是空的。
下面是加载树的初始视图时提取的服务器协议,其中预计将呈现根 (id=2159) 的两个子项(id 为 1 和 2):
1.getRoot: AsupoksEntities.Nomen[ id=2159 ] (Номенклатура)]]
2.getRowKey: this: AsupoksEntities.Nomen[ id=2159 ] (Номенклатура) id: 2159]]
3.getRowKey: this: AsupoksEntities.Nomen[ id=2159 ] (Номенклатура) id: 2159]]
4.getChildren for AsupoksEntities.Nomen[ id=2159 ] (Номенклатура): List: [AsupoksEntities.Nomen[ id=1 ] (Работы), AsupoksEntities.Nomen[ id=2 ] (Материалы)] ]]
5.getRowKey: this: AsupoksEntities.Nomen[ id=1 ] (Работы) id: 1]]
6.getRoot: AsupoksEntities.Nomen[ id=2159 ] (Номенклатура)]]
7.getChildren for AsupoksEntities.Nomen[ id=2159 ] (Номенклатура): List: [AsupoksEntities.Nomen[ id=1 ] (Работы), AsupoksEntities.Nomen[ id=2 ] (Материалы)] ]]
8.getChildren for AsupoksEntities.Nomen[ id=2159 ] (Номенклатура): List: [AsupoksEntities.Nomen[ id=1 ] (Работы), AsupoksEntities.Nomen[ id=2 ] (Материалы)] ]]
9.getData for AsupoksEntities.Nomen[ id=2 ] (Материалы)]]
10.getChildren for AsupoksEntities.Nomen[ id=2159 ] (Номенклатура): List: [AsupoksEntities.Nomen[ id=1 ] (Работы), AsupoksEntities.Nomen[ id=2 ] (Материалы)] ]]
11.getRowKey: this: AsupoksEntities.Nomen[ id=2 ] (Материалы) id: 2]]
12.getRoot: AsupoksEntities.Nomen[ id=2159 ] (Номенклатура)]]
13.getChildren for AsupoksEntities.Nomen[ id=2159 ] (Номенклатура): List: [AsupoksEntities.Nomen[ id=1 ] (Работы), AsupoksEntities.Nomen[ id=2 ] (Материалы)] ]]
14.getRoot: AsupoksEntities.Nomen[ id=2159 ] (Номенклатура)]]
15.getChildren for AsupoksEntities.Nomen[ id=2159 ] (Номенклатура): List: [AsupoksEntities.Nomen[ id=1 ] (Работы), AsupoksEntities.Nomen[ id=2 ] (Материалы)] ]]
16.getRoot: AsupoksEntities.Nomen[ id=2159 ] (Номенклатура)]]
17.getChildren for AsupoksEntities.Nomen[ id=2159 ] (Номенклатура): List: [AsupoksEntities.Nomen[ id=1 ] (Работы), AsupoksEntities.Nomen[ id=2 ] (Материалы)] ]]
18.getChildren for AsupoksEntities.Nomen[ id=2159 ] (Номенклатура): List: [AsupoksEntities.Nomen[ id=1 ] (Работы), AsupoksEntities.Nomen[ id=2 ] (Материалы)] ]]
19.getData for AsupoksEntities.Nomen[ id=1 ] (Работы)]]
20.getRoot: AsupoksEntities.Nomen[ id=2159 ] (Номенклатура)]]
21.getChildren for AsupoksEntities.Nomen[ id=2159 ] (Номенклатура): List: [AsupoksEntities.Nomen[ id=1 ] (Работы), AsupoksEntities.Nomen[ id=2 ] (Материалы)] ]]
22.getChildren for AsupoksEntities.Nomen[ id=2159 ] (Номенклатура): List: [AsupoksEntities.Nomen[ id=1 ] (Работы), AsupoksEntities.Nomen[ id=2 ] (Материалы)] ]]
23.getData for AsupoksEntities.Nomen[ id=2 ] (Материалы)]]
24.getRoot: AsupoksEntities.Nomen[ id=2159 ] (Номенклатура)]]
25.getChildren for AsupoksEntities.Nomen[ id=2159 ] (Номенклатура): List: [AsupoksEntities.Nomen[ id=1 ] (Работы), AsupoksEntities.Nomen[ id=2 ] (Материалы)] ]]
调用顺序看起来很奇怪。
日志第 5 行没有调用 getData(预期调用 getData,然后调用 getRowKey,如第 9,11 行)
对 ROOT 的 getChildren 调用过多(预期调用 getChildren,然后通过后续 getData 调用遍历 List。
我不明白出了什么问题。跟踪 getChildren 调用可以更深入地提供正确的树结构。集合被跟踪以被实例化。 (添加 FetchType.EAGER 没有任何改变)。我计划使用带有拖放功能的 p:tree 组件来实现层次编辑器,但现在停止。我不想在 DefaultTreeNode 中包含 Nomen 作为数据对象,然后复制实体类本身已经实现的自然树结构。然后同步两个父更改;-)
有人可以帮忙吗?
【问题讨论】:
标签: primefaces treenode