簡體   English   中英

JPA查詢::過濾外部聯接結果

[英]JPA Query :: Filtering outer join results

在發布此內容之前,我進行了很多研究,並且確實實現了我不喜歡的解決方法。 我嘗試了Hibernate的@Filter和@FilterDef注釋,但收效甚微,而且我還是不太喜歡該選項,因為它使我的持久層依賴於提供程序框架。 不過,我在此處包括一個特定於休眠的注釋,因此我的解決方案並非完全沒有特定於框架的代碼。

基本上,我有一個帶有家庭成員的Person類,其中包含其他Person的集合。 我想存檔數據,並且基本上從不物理刪除任何內容,因此應用程序中的所有主要對象都具有布爾“已刪除”值。

我的基本問題是,我無法找出用於過濾familyMembers集合的JPA查詢,在該查詢中,我只能檢索那些尚未從數據庫中刪除的家庭成員。

@Entity
@Table(name="person")
class Person {
    private boolean deleted; 
    private List<Person> familyMembers;

    @ManyToMany(targetEntity=Person.class, cascade={ CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH }, fetch=FetchType.LAZY)
    @JoinTable(name = "hp_person_family", 
        joinColumns = { @JoinColumn(name = "person_id") }, inverseJoinColumns = { @JoinColumn(name = "family_person_id") }
    )
    @LazyCollection(LazyCollectionOption.FALSE)
    public List<Person> getFamilyMembers() {
        return familyMembers;
    }

    @Column(name = "deleted_flag")
    @Type(type = "yes_no")
    public boolean isDeleted() {
        return deleted;
    }

}

在我的服務實現中,我有以下幾點:

String personQuery = "SELECT DISTINCT(p) FROM Person p "
        + "LEFT JOIN FETCH p.familyMembers pf " 
        + "WHERE p.deleted = false " 
        +   "AND pf.deleted = false"; 
List<Person> people = em.createQuery(personQuery, Person.class) 
        .getResultList(); 

僅返回那些擁有非空的familyMembers集合的人,而僅返回那些未被刪除的人。

接下來,我嘗試了:

String personQuery = "SELECT DISTINCT(p) FROM Person p "
        + "LEFT JOIN FETCH p.familyMembers pf " 
        + "WHERE p.deleted = false"; 
List<Person> people = em.createQuery(personQuery, Person.class) 
        .getResultList(); 

這帶來了太多的事情...所有未刪除的人,但他們的familyMembers可能已被刪除,他們仍然會被取回。

當我嘗試不同的“ ON”語句和我拼命知道不會起作用但無論如何嘗試的其他asinine組合時,出現了許多語法錯誤。

最后,我使用了第二個版本,然后使用了Predicate對象來過濾生成的familyMember集合。 我得到了想要的結果,但是這意味着在檢索到該集合后(在JDK1.8中使用Lambdas進行迭代!!!),只是為了過濾出壞人。

String personQuery = "SELECT DISTINCT(p) FROM Person p "
        + "LEFT JOIN FETCH p.familyMembers pf " 
        + "WHERE p.deleted = false"; 
List<Person> people = em.createQuery(personQuery, Person.class) 
        .getResultList(); 

filterPeopleResults(people); 




private void filterPeopleResults(List<Person> people) {
    if( people == null || people.isEmpty() ) return; 
    for(Person person : people) {
        removeDeletedFamilyMembers(person);
    }
}

private void removeDeletedFamilyMembers(Person person) {
    if( person.getFamilyMembers().isEmpty() == false ) {
        Predicate predicate = new Predicate() {
            @Override
            public boolean evaluate(Object obj) {
                if( ((Person)obj).isDeleted() ) return false; 
                return true; 
            }
        };
        CollectionUtils.filter(person.getFamilyMembers(), predicate);
    }
}

我考慮過將這種邏輯推到應用程序級別的可能性,因為我只會過濾那些我實際上想使用的Person對象。 我在使用JPA時是否還有其他選擇,或者其他一些巧妙的JPQL語法可以滿足我的需求?

好了,您可以在集合定義中添加@Where注釋(特定於休眠)。

另一個選擇是進行硬刪除並使用Hibernate Envers維護完整的審核歷史記錄。 因此,您始終可以從審核表中檢索已刪除的實體,並避免要求所有查詢和集合映射使用“ where Deleted = 0”的要求

http://www.jboss.org/envers

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM