2010-02-17 14 views
16

Podoba mi się pomysł nazwanych zapytań w WZP dla zapytań statycznych, które zamierzam zrobić, ale często chcę uzyskać wynik liczenia dla zapytania, a także listę wyników z pewnego podzbioru zapytania. Wolałbym nie pisać dwóch prawie identycznych nazwanych NamedQueries. Idealnie, co chciałbym mieć to coś w rodzaju:Czy istnieje sposób na uzyskanie rozmiaru licznika dla kwerendy nazwanej JPA z zestawem wyników?

@NamedQuery(name = "getAccounts", query = "SELECT a FROM Account") 
. 
. 
    Query q = em.createNamedQuery("getAccounts"); 
    List r = q.setFirstResult(s).setMaxResults(m).getResultList(); 
    int count = q.getCount(); 

Więc powiedzmy m wynosi 10, s ma wartość 0 i istnieją 400 wierszy w Rachunku. Oczekuję, że r będzie mieć listę 10 elementów, ale chciałbym wiedzieć, że jest ich łącznie 400 wierszy. Mógłbym napisać drugą @NamedQuery:

@NamedQuery(name = "getAccountCount", query = "SELECT COUNT(a) FROM Account") 

ale wydaje suchym naruszenie to zrobić jeśli mam zawsze tylko będzie chciał liczyć. W tym prostym przypadku łatwo jest zsynchronizować te dwie, ale jeśli zapytanie się zmieni, wydaje się mniej niż idealne, że muszę zaktualizować oba @NamedQueries, aby zachować wartości w linii.

Powszechnie stosowanym przykładem byłoby pobranie części podzbioru produktów, ale wymagające pewnego sposobu wskazania całkowitej liczby ("Wyświetlanie 1-10 z 400").

Odpowiedz

13

Rozwiązaniem, z którego skorzystałem, było stworzenie dwóch @NamedQuerys, jednego dla zestawu wyników i jednego dla zliczenia, ale przechwytywanie podstawowego zapytania w statycznym ciągu w celu utrzymania DRY i zapewnienia, że ​​oba zapytania pozostają spójne. Więc dla powyższego, że mam coś takiego:

@NamedQuery(name = "getAccounts", query = "SELECT a" + accountQuery) 
@NamedQuery(name = "getAccounts.count", query = "SELECT COUNT(a)" + accountQuery) 
. 
static final String accountQuery = " FROM Account"; 
. 
    Query q = em.createNamedQuery("getAccounts"); 
    List r = q.setFirstResult(s).setMaxResults(m).getResultList(); 
    int count = ((Long)em.createNamedQuery("getAccounts.count").getSingleResult()).intValue(); 

Oczywiście, z tego przykładu, organizm zapytanie jest trywialne i jest to przesada. Ale przy bardziej złożonych zapytaniach kończy się jedna definicja treści zapytania i może zapewnić synchronizację obu zapytań. Masz również tę zaletę, że kwerendy są prekompilowane, a przynajmniej z Eclipselink, otrzymujesz sprawdzanie poprawności podczas uruchamiania, a nie po wywołaniu zapytania.

Wykonując spójne nazewnictwo między dwoma zapytaniami, można owinąć treść kodu, aby uruchomić oba zestawy, opierając się na bazie nazwy zapytania.

+0

wreszcie działa również dla namedQueries! dziękuję – Zavael

+0

Interesujące, nie wiedziałem nawet, że podczas konfigurowania adnotacji można odwoływać się do statystyk statycznych. Jednak rozwiązanie, które nie wymagałoby dwóch oddzielnych nazwanych zapytań, nadal byłoby idealne, jak sądzę. – aroth

5

Korzystanie setFirstResult/setMaxResults zrobić nie powrócić podzbiór zbioru wynikowego, zapytanie nie nawet uruchamiane podczas wywołania tych metod, wpływają one wygenerowane zapytanie SELECT, które zostaną wykonane podczas wywoływania getResultList. Jeśli chcesz uzyskać całkowitą liczbę rekordów, będziesz musiał SELECT COUNT swoich jednostek w osobnej kwerendzie (zwykle przed do stronicowania).

Aby uzyskać pełny przykład, sprawdź numer Pagination of Data Sets in a Sample Application using JSF, Catalog Facade Stateless Session, and Java Persistence APIs.

+0

Tak. Chcę uzyskać pełną liczyć, że kwerenda spowoduje. Więc liczyć w przykładzie nie odpowiadają r.size() lub po prostu użyć tego. Potencjalnym przypadkiem użycia jest to, że chcę uzyskać stronę z wynikami dla list aukcji, ale aby pozwolić im na liczbę stron całkowitych, chciałbym, aby całkowita liczba z kwerendy, mimo że jestem tylko pobieranie 25 wyników. – Tim

+0

@Tim wyjaśniłem moją odpowiedź. Jeśli nadal nie jest jasne, daj mi znać. –

+0

Dzięki. Próbowałem wyjaśnić moje pytanie. Zasadniczo wiem, że modyfikatory zmieniają zapytanie przed jego uruchomieniem. Mam nadzieję, że uda mi się stworzyć pojedynczy @NamedQuery, który będzie stanowił podstawę do zwracania podzbioru, a także do liczenia, zamiast pisania jednego zapytania dla licznika i jednego dla zestawu zwrotów. Idealnie nadal przy użyciu @NamedQuery. Sprawdzę link, do którego się odwołujesz. – Tim

1

oh dobrze można użyć, aby uzyskać introspekcji nazwanych zapytań adnotacje jak:

String getNamedQueryCode(Class<? extends Object> clazz, String namedQueryKey) { 
    NamedQueries namedQueriesAnnotation = clazz.getAnnotation(NamedQueries.class); 
    NamedQuery[] namedQueryAnnotations = namedQueriesAnnotation.value(); 

    String code = null; 
    for (NamedQuery namedQuery : namedQueryAnnotations) { 
     if (namedQuery.name().equals(namedQueryKey)) { 
      code = namedQuery.query(); 
      break; 
     } 
    } 

    if (code == null) { 
     if (clazz.getSuperclass().getAnnotation(MappedSuperclass.class) != null) { 
      code = getNamedQueryCode(clazz.getSuperclass(), namedQueryKey); 
     } 
    } 

    //if not found 
    return code; 
} 
+0

Nie wiem, jak to dotyczy mojego pytania. Chcę używać NamedQuery dla korzyści prekompilacji, buforowania i innych optymalizacji. Chcę, aby te dwa zapytania były identyczne, z wyjątkiem jednego zwracającego wyniki i jednego zwracającego liczbę. I chcę śledzić DRY, a nie kopiować i wklejać warunkowej klauzuli. – Tim

Powiązane problemy