JPA / Hibernate在setter中使用关联对象,而field为null

时间:2011-07-01 12:50:01

标签: hibernate jpa

我的代码看起来像这样。为什么我在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,所以请帮忙。

2 个答案:

答案 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。