【问题标题】:JPA/Hibernate using associated object in setters while fields are nullJPA/Hibernate 在设置器中使用关联对象,而字段为空
【发布时间】:2011-07-01 12:50:01
【问题描述】:

我的代码如下所示。为什么我在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

    }

我是 n00b,所以请帮忙。

【问题讨论】:

  • 如果您调试此代码并在 setChildren(...) 中设置断点,是否所有子节点对象上的字段(可能除了 @Id)都设置为 null?
  • 正确。除@Id 之外的所有字段均为null。请帮忙
  • 请参阅stackoverflow.com/questions/6217096/…,了解与集合类似的问题。

标签: hibernate jpa


【解决方案1】:

这是一个猜测,但我怀疑 Node.setChildren() 是在子对象实际上被 Hibernate 的支持 SQL 查询中的数据填充之前被调用的。 Hibernate 有时会创建只设置了 @Id 值的对象;如果您阅读有关惰性代理的文档,您应该会看到相关证据。我怀疑 Hibernate 已经创建了子节点对象,但还没有用数据填充它们,因为它需要先填充父节点。基本上你的二传手在这个过程中开得太早了。

您可以通过调试代码并在 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 方法中,并在查询后手动调用它。

【讨论】:

  • 有效的是我切换到 Hibernate 的所有字段直接访问,并按照您的建议将逻辑移动到 getter。它现在可以工作了。
【解决方案2】:

如果孩子的名字为空,那么编写的代码会很高兴地将空添加到您的 childrenNames 集合中。

【讨论】:

  • 孩子的名字不为空。事实上,它们稍后会被填充。只有在 setter 时,它才会返回为 null。
猜你喜欢
  • 2023-01-11
  • 2015-02-22
  • 2017-02-18
  • 2011-03-14
  • 2011-06-25
  • 2012-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多