Reputation: 917
I have this object that builds a tree in the database. Each node points to its parent, or is null. I need this relationship to be bi-directional, so each node also knows its children nodes. When a node is deleted IS_ACTIVE gets set to false. How do I modify these annotations such that only children with IS_ACTIVE set to true get loaded?
@Entity
@Table(name = "node")
public class Node {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "PARENT_NODE_ID")
private Node parentNode;
@OneToMany(mappedBy = "parentNode", fetch = FetchType.LAZY)
private Set<Node> childrenNodes;
@Column(name = "IS_ACTIVE", nullable = false)
private boolean isActive;
//other fields that shouldn't matter left out.
}
Currently my unit tests are running in the same transaction, so I have to use session.refresh(node) to get the children nodes to load at all, but every time it loads all of the children ignoring my filters and where clause.
What is the correct way to annotate this class so the children only the active children load?
Does it matter if the children are lazy-loaded?
*Please note I have search for answers to this.
As an example, this question seems related, but the solution does not work. I belive it is different because my join is self-referencing... but it might be due to something else I am missing. annotation to filter results of a @OneToMany association
Upvotes: 1
Views: 809
Reputation: 2027
When you say "only children with IS_ACTIVE set to true get loaded", you are defining a business rule and therefore you have to instruct Hibernate to follow it somehow.
Using "session.get(object)" and "session.refresh(object)" you are asking Hibernate to get an Entity, however you did not instruct Hibernate to follow your business rule.
Briefly speaking, there are two ways to solve your issue:
(1): Let Hibernate fetch all "childrenNodes", subsequently you can write another method to return only children with IS_ACTIVE = true. Something like:
public Set<Node> getActiveChildrenNodes(Node n){
Set<Node> result = new HashSet();
for(Node cn : n.getChildrenNodes()){
if(cn.isActive)
result.add(cn);
}
return result;
}
As you may see, this approach may have a bad performance if you have several records in your database.
(2): A better options would be to load only children with IS_ACTIVE = true. So, you can write something like:
public List getActiveChildrenNodes(Node n, Session s){
return = session
.createQuery("FROM Node WHERE Node.id = :pId AND Node.childrenNodes.isActive : pIsActive")
.setParameter("pId", n.getId())
.setParameter("pIsActive", true)
.list();
}
There are several ways to do it, I hope this explanation can help you.
Cheers,
Upvotes: 1