2011-12-15 4 views
11

У меня есть несколько объектов, которые запрашиваются с помощью запроса критериев JPA2.Как получить все данные в одном запросе

Я могу присоединиться к двум из этих лиц и получить результат сразу:

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); 

Тогда я пытаюсь соединить дополнительную таблицу так:

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

я получаю следующее сообщение об ошибке :

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] 

Как я могу сказать JPA/Hibernate, что он должен выбрать все объекты одновременно?

ответ

6

не то, что речь идет о JPA, вы можете цепи присоединиться к распаковывает, в запросах Критерии API (цитата из спецификации):

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.

И это также не поддерживается в запросах 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.

С HQL представляется возможным: Hibernate documentation EclipseLink не предоставляет такого расширения, поэтому синтаксис следующего запроса принимается Hibernate, но не EclipseLink:

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

В EclipseLink это можно сделать через query hints.

11

С JPA «некоторые диалекты JPA» вы можете связать выборки, но я не думаю, что вы можете/должны делать как соединение, так и соединение.

Например, если у нас есть Program, который имеет один-ко-многим отношения к Reward, что имеет отношение к Duration, следующие JPQL бы получить конкретный экземпляр с наградами и продолжительность предварительного неправдоподобно:

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

} 

с эквивалентным кодом Criteria:

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(); 

Обратите внимание, что промежуточное переменное вознаграждение и продолжительность здесь не нужны, но они вдается в информационных целях. root.fetch("rewards", JoinType.LEFT).fetch("duration", JoinType.LEFT) будет иметь тот же эффект.

+0

Он работает из-за расширений поставщика в некоторых реализациях (например, Hibernate). В JPA вообще этот запрос JPQL не работает, потому что в этом случае не требуется поддержка цепочки и псевдонимов в соответствии со спецификацией. –

+1

Спасибо за разъяснение Микко. Это довольно неприятно, что такие расширения молча активируются, поэтому вы используете их, не осознавая этого. –

+0

Спасибо. Использование выборки без использования соединения до решения проблемы. Однако я хотел бы поставить предикат на объединенную таблицу. как я могу это сделать? До того, как я использовал следующую конструкцию: Присоединиться ladung = from.join ("ladung"); ladung.get ("fzadresse"). In (adressen); – Stinnux

Смежные вопросы