JPA/Hibernate using associated object in setters while fields are null
My code looks like this. Why do I get name in setChildren()
as 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开发者_如何学Go(child.getName()); //Adds NULL !!!!!!
}
}
// Other Setters
}
Am n00b, so please help with this.
This is a guess but I suspect that Node.setChildren() is being called before the child objects have actually been populated with the data from the backing SQL query by Hibernate. Hibernate will sometimes create objects with only their @Id value set; if you read the documentation about lazy proxies you should see evidence of that. I suspect then that Hibernate has created the child Node objects but hasn't populated them with data yet because it needs to populate the parent Node first. Basically your setter is firing too early in the process.
You could verify this by debugging the code and adding a breakpoint in setChildren() and setName(). You don't show a setName() method in the code above but I assume you just omitted it. Also check the stack at your breakpoint to get a sense of what Hibernate is doing at the time your setter is invoked.
One workaround would be to add the logic from setChildren() into getChildren() like this:
@Transient public Set<String> getChildrenNames() {
if (children.size() != childrenNames.size() {
childrenNames.removeAll();
for(Node child : children) {
childrenNames.add(child.getName());
}
}
return childrenNames;
}
This could should only execute once and by the time the getter is invoked the data in the children should be populated. Or you could put the logic that populates "childrenNames" into a non getter/setter method and invoke it manually after the query.
If the child's name is null, then the code as written will happily add null to your childrenNames set.
精彩评论