在發佈之前,我研究了很多,我確實實施了一個我不喜歡的解決方法。我嘗試了Hibernate的@Filter和@FilterDef註解,但很少取得成功,因爲它使得我的持久層依賴於提供者框架。不過,我在這裏包含了一個hibernate特定的註釋,所以我的解決方案並不完全沒有框架特定的代碼。JPA Query ::篩選外部連接結果
基本上,我有一個人類與家庭成員,其中包含其他人的集合。我想歸檔我的數據,基本上從不物理刪除任何東西,所以應用程序中的所有主要對象都有一個布爾值「已刪除」值。
我的基本問題是,我找不到一個JPA查詢過濾familyMembers集合,我只能檢索那些尚未從數據庫中刪除的家族成員。
@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語法,會給我我想要的?