2012-09-27 15 views
42

Chciałbym wybrać tylko określone kolumny (na przykład SELECT a FROM b). Mam rodzajowe DAO i co wymyśliłem to:Interfejs API JPA i kryteriów - wybierz tylko określone kolumny

public List<T> getAll(boolean idAndVersionOnly) { 
    CriteriaBuilder builder = manager.getCriteriaBuilder(); 
    CriteriaQuery<T> criteria = builder.createQuery(entityClazz); 
    Root<T> root = criteria.from(entityClazz); 
    if (idAndVersionOnly) { 
     criteria.select(root.get("ID").get("VERSION")); // HERE IS ERROR 
    } else { 
     criteria.select(root); 
    } 
    return manager.createQuery(criteria).getResultList(); 
} 

a błąd jest: The method select(Selection<? extends T>) in the type CriteriaQuery<T> is not applicable for the arguments (Path<Object>). Jak mam to zmienić? Chcę uzyskać obiekt typu T, który ma tylko pola ID i VERSION, a wszystkie pozostałe to null.

Wpisz T rozszerza AbstractEntity, który ma te 2 pola.

entityClazz to T.class.

Odpowiedz

58

Jednym ze sposobów uzyskiwania tylko niektórych kolumn JPA jest zapytanie o obiekt Tuple.

W twoim przypadku trzeba by napisać coś takiego:

CriteriaQuery<Tuple> cq = builder.createTupleQuery(); 
// write the Root, Path elements as usual 
Root<EntityClazz> root = cq.from(EntityClazz.class); 
cq.multiselect(root.get(EntityClazz_.ID), root.get(EntityClazz_.VERSION)); //using metamodel 
List<Tuple> tupleResult = em.createQuery(cq).getResultList(); 
for (Tuple t : tupleResult) { 
    Long id = (Long) t.get(0); 
    Long version = (Long) t.get(1); 
} 

Innym podejściem jest możliwe, jeśli masz klasę reprezentującą wynik, jak T w Twoim przypadku. T nie musi być klasą Entity. Jeśli T ma konstruktora takiego:

public T(Long id, Long version) 

następnie można użyć T bezpośrednio w konstruktorze CriteriaQuery:

CriteriaQuery<T> cq = builder.createQuery(T.class); 
// write the Root, Path elements as usual 
Root<EntityClazz> root = cq.from(EntityClazz.class); 
cq.multiselect(root.get(EntityClazz_.ID), root.get(EntityClazz_.VERSION)); //using metamodel 
List<T> result = em.createQuery(cq).getResultList(); 

Zobacz ten link dla dalszego odniesienia.

2

Po pierwsze, tak naprawdę nie rozumiem, dlaczego chciałbyś, aby obiekt posiadający tylko ID i wersję oraz wszystkie inne rekwizyty miały wartość zerową. Jednak tutaj jest jakiś kod, który zrobi to za Ciebie (który nie używa JPA Em, ale normalny Hibernate.) Zakładam, że możesz znaleźć równoważność w JPA lub po prostu uzyskać sesję Hibernacji obj od delegata em Accessing Hibernate Session from EJB using EntityManager ):

List<T> results = session.createCriteria(entityClazz) 
    .setProjection(Projections.projectionList() 
     .add(Property.forName("ID")) 
     .add(Property.forName("VERSION")) 
    ) 
    .setResultTransformer(Transformers.aliasToBean(entityClazz); 
    .list(); 

ta zwróci listę obiektów posiadających identyfikator i zestaw wersję i wszystkie inne rekwizyty do null, jak transformator aliasToBean nie będą mogli je znaleźć. Znowu jestem niepewny, że mogę wymyślić sytuację, w której chciałbym to zrobić.

+0

Dziękuję. Chcę go użyć w moim serwisie internetowym. Klient żąda listy "czegoś" zawierającego tylko identyfikatory i wersje. Następnie porównuje go do pamięci podręcznej i żąda pełnych obiektów, które się zmieniły. Brzmi rozsądnie? – BartoszCichecki

+0

Czy to oszczędza przepustowość sieci? Zakładam, że zależy to od danych, ale jeśli spodziewasz się, że twoje dane będą się często zmieniać, możesz zmarnować większą przepustowość z powodu narzutów tcp/ip tworzenia dwóch próśb niż zapisywania od wysyłania "pustych" kopii. Może warto to sprawdzić? –

+1

Tak, wiem. Używam go tylko dla danych, które nie będą się tak często zmieniać. – BartoszCichecki

Powiązane problemy