2013-03-27 66 views
1

我有這個對象在數據庫中構建樹。每個節點指向其父節點,或者爲空。我需要這種關係是雙向的,所以每個節點也知道它的子節點。當一個節點被刪除時,IS_ACTIVE被設置爲false。我如何修改這些註釋,以便只有IS_ACTIVE設置爲true的孩子才能加載?嘗試將過濾器添加到休眠自引用OneToMany加入

@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(節點)來獲取子節點去加載,但每次它加載所有的孩子無視我過濾器和where子句。

什麼是正確的方式來註釋這個類,以便孩子只有活躍的孩子加載?

孩子們是否懶惰裝載是否重要?

*請注意我已經在尋找答案。

作爲一個例子,這個問題似乎相關,但解決方案不起作用。我相信它是不同的,因爲我的連接是自引用的...但它可能是由於我缺少的其他東西。 annotation to filter results of a @OneToMany association

+1

嗨Luiggi,它看起來是對我來說。你能和我們分享你的單元測試嗎?我對Criteria/HQL部分特別感興趣。乾杯, – Rafa 2013-03-28 01:39:06

+0

我沒有使用Criteria或HQL ...我使用session.get(object);和session.refresh(object);這可能是問題的一部分嗎? – Anthony 2013-03-28 20:50:29

回答

1

當您說「只有IS_ACTIVE設置爲true的孩子才能加載」時,您正在定義一個業務規則,因此您必須指示Hibernate以某種方式關注它。

使用「session.get(object)」和「session.refresh(object)」,你要求Hibernate獲得一個實體,但是你沒有指示Hibernate遵循你的業務規則。

簡單地說,有兩種方法可以解決您的問題:

(1):讓休眠獲取所有「childrenNodes」,隨後你可以寫另一個方法與IS_ACTIVE =真返回獨生子女。例如:

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

有幾種方式做到這一點,我希望這個解釋可以幫助你。

乾杯,