简体   繁体   English

尝试添加过滤器以休眠自引用OneToMany联接

[英]Trying to add filter to hibernate self-referencing OneToMany join

I have this object that builds a tree in the database. 我有一个在数据库中构建树的对象。 Each node points to its parent, or is null. 每个节点都指向其父节点,或者为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. 删除节点后,IS_ACTIVE设置为false。 How do I modify these annotations such that only children with IS_ACTIVE set to true get loaded? 如何修改这些注释,以便仅将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.
}

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. 当前,我的单元测试正在同一事务中运行,因此我必须使用session.refresh(node)来完全加载子节点,但是每次加载所有子节点时,都会忽略我的过滤器和where子句。

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 注释以过滤@OneToMany关联的结果

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. 当您说“仅将IS_ACTIVE设置为true的子代加载”时,您正在定义业务规则,因此必须指示Hibernate以某种方式遵循它。

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. 您正在使用“ session.get(对象)”和“ session.refresh(对象)”要求Hibernate获取实体,但是您并未指示Hibernate遵循您的业务规则。

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. (1):让Hibernate提取所有“ childrenNodes”,随后您可以编写另一种方法以仅返回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. (2):更好的选择是仅加载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, 干杯,

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM