2013-06-08 11 views
8

Próbuję utworzyć następujące zdanie, używając kryteriów api w JPA (eclipselink), to proste pytanie, czy istnieje jakiś użytkownik w jakiejś kategoriiW kryteriach jpa "w przypadku, gdy istnieje co najmniej jeden wiersz, zwracana jest prawda"

zdanie chcę:

SELECT 
    CASE 
    WHEN EXISTS 
      (SELECT * FROM user WHERE category = ?) 
    THEN true 
    ELSE false 
    END 
bind => [10] 

ja próbuje przy użyciu tego kodu:

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); 
CriteriaQuery<Boolean> criteriaQuery = criteriaBuilder.createQuery(Boolean.class); 
Root<T> root = criteriaQuery.from(tclass); 

Subquery<T> subquery = criteriaQuery.subquery(tclass); 
Root<T> subroot = subquery.from(tclass); 
subquery.select(subroot); 

Predicate subPredicate = criteriaBuilder.equal(subroot.get("category"),category); 
subquery.where(subPredicate); 

Predicate predicateExists = criteriaBuilder.exists(subquery); 

Case<Boolean> booleancase = criteriaBuilder.<Boolean>selectCase(); 
Expression<Boolean> booleanExpression = 
    booleancase.when(predicateExists,true) 
    .otherwise(false); 

criteriaQuery.select(booleanExpression); 

TypedQuery<Boolean> typedQuery = entityManager.createQuery(criteriaQuery); 
typedQuery.getResultList(); 

Niestety zdanie mam jest kontynuacją, chcę usunąć ostatni „od użytkownika”:

SELECT 
    CASE 
     WHEN EXISTS 
      (SELECT ? FROM user t1 WHERE (t1.category = ?)) 
    THEN ? 
    ELSE ? 
    END 
FROM user t0  
bind => [1, 110, true, false] 

Każdy pomysł?

+0

Co się stanie, jeśli używasz subroot zamiast root, w subPredicate ? – perissf

+0

Przepraszamy, to subroot w subpredicate. Piszę źle w stackoverflow (już poprawiam pytanie). Dzięki, ale to nie rozwiązuje mojego problemu: P – Troncador

+0

Dlaczego chcesz ten złożony i nieczytelny kod java, jeśli masz już proste i jasne zapytania SQL? – jbaliuka

Odpowiedz

0

końcu obejść: P

TypedQuery<Boolean> typedQuery = 
    entityManager.createQuery(criteriaQuery).setMaxResults(1); 

Wówczas zdanie (to nie to samo, ale jest bardzo blisko):

SELECT 
    CASE 
     WHEN EXISTS 
      (SELECT ? FROM user t1 WHERE (t1.category = ?)) 
    THEN ? 
    ELSE ? 
    END 
FROM user t0 LIMIT ?, ? 
bind => [1, 110, true, false,0,1] 
1

Niestety, JPA nie obsługuje wybierania danych bez encji (tabela). Nawet standardowy SQL92 tego nie obsługuje - zobacz, jak możesz wybrać bez tabeli w różnych bazach danych: http://en.wikibooks.org/wiki/SQL_Dialects_Reference/Select_queries/Select_without_tables

W standardzie SQL92 musisz podać tabelę w klauzuli SELECT.

JPA jest również powszechnie akceptowanym standardem i zwykle nie zapewnia niestandardowych funkcji, a nawet wiele standardowych funkcji SQL przychodzi tylko w najnowszych wersjach JPA (na przykład zagnieżdżone selekcje pojawiły się dopiero niedawno z JPA 2.1 w JavaEE 7).

Rozwiązaniem jest wybór z jakiejś encji, która zawsze zawiera co najmniej jeden wiersz w bazie danych, i ograniczenie wyników do maks. 1 za pomocą zapytania.setMaxResults (1). Jeszcze lepiej jest stworzyć manekin, który zawsze ma 1 wiersz, a jego zawartość nigdy się nie zmienia. Zwiększyłoby to wydajność wyboru.