2011-07-18 82 views
7

我不知道如何使JAP標準查詢結束與布爾輸出。如何正確確定「存在」JPA Criteria Query子句是否返回true或false?

的目標是有一個標準的查詢時,甲骨文呈現,看起來像這樣:

select 1 from dual where exists (...); 

where exists (...)部分我用的子查詢一樣,我與外部查詢掙扎。

而這個的實際用法是確定exists子句中的子查詢是否返回truefalse

這是我得到:

CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); 

CriteriaQuery<Object> query = criteriaBuilder.createQuery(); 
query.from(Boolean.class); 
query.select(criteriaBuilder.literal(true)); 

Subquery<Location> subquery = query.subquery(Location.class); 
Root<Location> subRootEntity = subquery.from(Location.class); 
subquery.select(subRootEntity); 

Path<?> attributePath = subRootEntity.get("State"); 
Predicate predicate = criteriaBuilder.equal(attributePath, criteriaBuilder.literal("TX")); 
subquery.where(predicate); 
query.where(criteriaBuilder.exists(subquery)); 

TypedQuery<Object> typedQuery = em.createQuery(query); 

但最後一行失敗布爾說不是一個實體。我認爲我的問題不知道如何表達查詢的「from」部分,因爲結果將爲1或0,true或false,而不是實體。

我知道我可以檢索任何實體,然後檢查結果列表是否具有大小1,但我試圖學習如何獲得布爾結果直接避免不必要的檢索這些列的任務,也學習怎麼做。

這可能嗎?

謝謝! Eduardo

+2

不,你不能直接這樣做,但一個共同的方法是檢查結果集即的計數,如果計數大於零,則真,否則返回false。 – Shahzeb

回答

6

你可以爲一個屬性(例如標識)做選擇並設置最大返回結果爲1,這樣,你要確保數據庫沒有做更多的工作比必要(如計算所有實例)。然後,您的結果列表將爲空(exists = false)或有一個元素(exists = true)。

+0

這就是我一直在尋找的一種方法,在沒有DBMS超過必要的情況下完成工作。謝謝!! –

0

我認爲問題在於query.from(Boolean.class)。它試圖創建一個「從布爾選擇對象」查詢。如果你想要一個布爾值作爲返回類型,你需要使用

CriteriaQuery<Boolean> query = criteriaBuilder.createQuery(Boolean.class) 

然後從任何現有的實體表查詢來創建一個有效的查詢(可能是從子查詢的表)。除了如果您設法映射雙重表格,我不認爲這是從雙重作品創建的。

-2

是否有任何理由,所有的邏輯必須在JPA?如果沒有,爲什麼不使用SELECT COUNT,然後使用條件來設置布爾值?

Boolean exists = false; 
int count = selectCountQuery(); 
if (count > 0) { 
    exists = true; 
} 
10

是的,這是可能的。假設您有一個對應於您的dual表的實體,您將需要在CriteriaQuery#from中使用該實體類。

CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); 

CriteriaQuery<Boolean> query = criteriaBuilder.createQuery(Boolean.class); 
query.from(dual.class); 
query.select(criteriaBuilder.literal(true)); 

Subquery<Location> subquery = query.subquery(Location.class); 
Root<Location> subRootEntity = subquery.from(Location.class); 
subquery.select(subRootEntity); 

Path<?> attributePath = subRootEntity.get("State"); 
Predicate predicate = criteriaBuilder.equal(attributePath, criteriaBuilder.literal("TX")); 
subquery.where(predicate); 
query.where(criteriaBuilder.exists(subquery)); 

TypedQuery<Boolean> typedQuery = em.createQuery(query); 
2

我知道這是一個老問題,但對於其他人看:你能不能試着使用Spring的JPA @Query註釋和選擇的情況下查詢(取決於你的數據庫實現)與返回布爾值的方法。例如(MySQL的):

@Query("SELECT CASE WHEN COUNT(l) > 0 THEN TRUE ELSE FALSE END FROM Location l WHERE l.state=?1") 
boolean locationForStateExists(String state); 

有時候,只是使用@Query查詢字符串可以是一個生命的救星,當一個名爲JPA或查詢生成器方法不太做你想讓他們什麼。

+0

這依賴於'count()',這是基本問題。 Hibernate不支持「exists」關鍵字,除了where語句之外,它不能完成OP要求的內容。選擇「count」可能會非常慢(取決於where子句的複雜性,索引的存在等),而exists子句在第一次出現時會快速失敗。這真是一種恥辱JPA/Hibernate不支持這種簡單的優化。 –

1

休眠5工作:

Subquery<Integer> subquery = query.subquery(Integer.class); 
Root<Location> subRootEntity = subquery.from(Location.class); 
subquery.select(criteriaBuilder.literal(1)); 

Path<?> attributePath = subRootEntity.get("State"); 
Predicate predicate = criteriaBuilder.equal(attributePath, criteriaBuilder.literal("TX")); 
subquery.where(predicate); 
query.where(criteriaBuilder.exists(subquery)); 
+0

感謝您的更新! –

相關問題