试图将过滤器添加到休眠自引用OneToMany连接

时间:2013-03-27 21:59:56

标签: java hibernate

我有这个对象在数据库中构建一个树。每个节点都指向其父节点,或者为null。我需要这种关系是双向的,因此每个节点也知道它的子节点。删除节点时,IS_ACTIVE设置为false。如何修改这些注释,以便只有IS_ACTIVE设置为true的子项才会被加载?

@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.
}

目前我的单元测试在同一个事务中运行,所以我必须使用session.refresh(node)来获取子节点才能加载,但每次加载所有子节点时忽略我的过滤器和where子句

注释此类的正确方法是什么,以便只有活动子项加载的子项?

孩子们是否懒惰是否重要?

*请注意我已经找到了答案。

举个例子,这个问题似乎有关系,但解决方案不起作用。我相信它是不同的,因为我的加入是自我引用...但它可能是由于我缺少的其他东西。 annotation to filter results of a @OneToMany association

1 个答案:

答案 0 :(得分:1)

当你说“只有IS_ACTIVE设置为true的孩子被加载”时,你正在定义一个业务规则,因此你必须指示Hibernate以某种方式遵循它。

使用“session.get(object)”和“session.refresh(object)”你要求Hibernate获得一个实体,但是你并没有指示Hibernate遵循你的业务规则。

简而言之,有两种方法可以解决您的问题:

(1):让Hibernate获取所有“childrenNodes”,然后你可以编写另一个方法来只返回IS_ACTIVE = true的子节点。类似的东西:

public Set<Node> getActiveChildrenNodes(Node n){
   Set<Node> result = new HashSet(); 
   for(Node cn : n.getChildrenNodes()){
        if(cn.isActive)
        result.add(cn);
    }
   return result;
}

正如您所看到的,如果您的数据库中有多条记录,这种方法的性能可能会很差。

(2):更好的选择是仅加载IS_ACTIVE = true的孩子。所以,你可以这样写:

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();
}

有几种方法可以做到,我希望这个解释可以帮到你。

干杯,