2011-12-15 14 views
11

Mam wiele obiektów, które są sprawdzane za pomocą kwerendy kryteriów JPA2.Jak pobrać wszystkie dane w jednym zapytaniu

Jestem w stanie dołączyć do dwóch z tych jednostek i uzyskać wynik na raz:

CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); 
CriteriaQuery<LadungRgvorschlag> criteriaQuery = criteriaBuilder.createQuery(LadungRgvorschlag.class); 
Root<LadungRgvorschlag> from = criteriaQuery.from(LadungRgvorschlag.class); 
Join<Object, Object> ladung = from.join("ladung"); 

from.fetch("ladung", JoinType.INNER); 

potem spróbować dołączyć dodatkową tabelę tak:

ladung.join("ladBerechnet"); 
ladung.fetch("ladBerechnet", JoinType.LEFT); 

pojawia się następujący błąd :

org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=generatedAlias3,role=null,tableName=ladberechnet,tableAlias=ladberechn3_,origin=ladungen ladung1_,columns={ladung1_.id ,className=de.schuechen.beans.tms.master.LadBerechnet}}] [select generatedAlias0 from de.schuechen.beans.tms.master.LadungRgvorschlag as generatedAlias0 inner join generatedAlias0.ladung as generatedAlias1 inner join generatedAlias1.ladBerechnet as generatedAlias2 left join fetch generatedAlias1.ladBerechnet as generatedAlias3 inner join fetch generatedAlias0.ladung as generatedAlias4 where (generatedAlias0.erledigt is null) and (generatedAlias0.belegart in (:param0, :param1)) and (generatedAlias1.fzadresse in (:param2, :param3)) and (generatedAlias1.zudatum<=:param4) and (1=1) order by generatedAlias0.belegart asc, generatedAlias1.fzadresse asc, generatedAlias1.zudatum asc, generatedAlias1.zulkw asc] 

Jak mogę powiedzieć WZP/Hibernacja, że ​​powinien wybrać wszystkie podmioty na raz?

Odpowiedz

6

nie Co chodzi o JPA, można łańcuch dołączyć pobieraniom w zapytaniach Criteria API (cytat ze specyfikacji):

An association or attribute referenced by the fetch method must be referenced from an entity or embeddable that is returned as the result of the query. A fetch join has the same join semantics as the corresponding inner or outer join, except that the related objects are not top-level objects in the query result and cannot be referenced elsewhere by the query.

I to również nie jest obsługiwane w zapytaniach JPQL:

The association referenced by the right side of the FETCH JOIN clause must be an association or element collection that is referenced from an entity or embeddable that is returned as a result of the query.

It is not permitted to specify an identification variable for the objects referenced by the right side of the FETCH JOIN clause, and hence references to the implicitly fetched entities or elements cannot appear elsewhere in the query.

Z HQL wydaje się to możliwe: Hibernate documentation EclipseLink nie zapewnia takiego rozszerzenia, więc składnia następującego zapytania jest akceptowana przez Hibernate, ale nie przez EclipseLink:

SELECT a FROM A a LEFT JOIN FETCH a.bb b LEFT JOIN FETCH b.cc 

W EclipseLink można to zrobić przez query hints.

11

Z JPA "niektóre dialekty WZP" można łączyć przyłączyć pobierania, ale nie sądzę, że można/powinien zrobić zarówno dołączyć i dołączyć pobrać.

Na przykład, jeśli mamy Program który ma relację jeden-do-wielu do Reward który ma związku z Duration następujące JPQL dostanie konkretny przypadek z nagród i czas trwania wstępnie naciągane:

SELECT DISTINCT 
    program 
FROM 
    Program _program 
     LEFT JOIN FETCH 
    _program.rewards _reward 
     LEFT JOIN FETCH 
    _reward.duration _duration 
WHERE 
    _program.id = :programId 

} 

z ekwiwalentem kodu kryteria:

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

Fetch<Program, Reward> reward = root.fetch("rewards", JoinType.LEFT); 
Fetch<Reward, Duration> duration = reward.fetch("duration", JoinType.LEFT); 

criteriaQuery.where(criteriaBuilder.equal(root.get("id"), programId)); 

TypedQuery<program> query = entityManager.createQuery(criteriaQuery); 

return query.getSingleResult(); 

Zauważ, że pośredni zmienne wynagrodzenie i czas nie są tu potrzebne, ale są wcina w celach informacyjnych. root.fetch("rewards", JoinType.LEFT).fetch("duration", JoinType.LEFT) miałby taki sam efekt.

+0

Działa z powodu rozszerzeń dostawców w niektórych implementacjach (takich jak na przykład Hibernacja). W JPA ogólnie to zapytanie JPQL nie działa, ponieważ takie połączenie i aliasy w tym przypadku nie muszą być obsługiwane zgodnie ze specyfikacją. –

+1

Dzięki za wyjaśnienie Mikko. To dość nieprzyjemne, że takie rozszerzenia są cicho aktywowane, więc używasz ich nie zdając sobie z tego sprawy. –

+0

Dzięki dotychczasowe. Używanie pobierania bez użycia łączenia przed rozwiązaniem problemu. Jednak chciałbym umieścić predykat na złączonym stole. jak mogłem to zrobić? Zanim użyłem następującej konstrukcji: Dołącz ladung = from.join ("ladung"); ladung.get ("fzadresse"). In (adressen); – Stinnux