我的代码看起来像这样。为什么我在setChildren()
中将名称命名为null
??
public class Node {
private String id, name, parentName;
private Set<Node> children = new HashSet<Node>();
private Node parent;
private Set<String> childrenNames = new HashSet<String>();
@Id @GeneratedValue public String getId() { return id; }
public String getName() {return name;}
@ManyToOne @JoinColumn(name="PARENT_ID") public Node getParent(){retrun parent;}
@OneToMany(cascade=CascadeType.ALL, mappedBy="parent", fetch=FetchType.EAGER)
public Set<Client> getChildren(){return Collections.unmodifiableSet(children)}
@Transient public String getParentName() { return parentName;}
@Transient public Set<String> getChildrenNames() {return childrenNames;}
// PROBLEM here ------------
public void setChildren(Set<Node> children) {
this.children = children;
for(Node child : children) {
childrenNames.add(child.getName()); //Adds NULL !!!!!!
}
}
// Other Setters
}
am n00b,所以请帮忙。
答案 0 :(得分:2)
这是猜测,但我怀疑在使用Hibernate支持SQL查询的数据实际填充了子对象之前,正在调用Node.setChildren()。 Hibernate有时会创建只设置了@Id值的对象;如果你阅读有关懒惰代理的文档,你应该看到这个的证据。我怀疑Hibernate已经创建了子Node对象,但尚未用数据填充它们,因为它需要首先填充父节点。基本上你的制定者在这个过程中过早发射。
您可以通过调试代码并在setChildren()和setName()中添加断点来验证这一点。您没有在上面的代码中显示setName()方法,但我假设您只是省略了它。还要检查断点处的堆栈,以了解在调用setter时Hibernate正在做什么。
一种解决方法是将setChildren()中的逻辑添加到getChildren()中,如下所示:
@Transient public Set<String> getChildrenNames() {
if (children.size() != childrenNames.size() {
childrenNames.removeAll();
for(Node child : children) {
childrenNames.add(child.getName());
}
}
return childrenNames;
}
这应该只执行一次,并且在调用getter时应该填充子项中的数据。或者您可以将填充“childrenNames”的逻辑放入非getter / setter方法,并在查询后手动调用它。
答案 1 :(得分:1)
如果孩子的名字为null,那么写的代码将很乐意为你的childrenNames集添加null。