Как получить все данные в одном запросе
У меня есть несколько объектов, которые запрашиваются с помощью запроса критериев 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, что он должен сразу выбрать все объекты?
Ответы
Ответ 1
С помощью 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
}
С эквивалентным кодом критериев:
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)
будет иметь тот же эффект.
Ответ 2
Что касается JPA, вы не можете связать выборки в запросах API Criteria (цитата из спецификации):
Связь или атрибут, на который ссылается метод выборки, должен быть ссылается от объекта или встраиваемого, который возвращается как результат запроса. Соединение fetch имеет ту же самую семантику соединения, что и соответствующее внутреннее или внешнее соединение, за исключением того, что связанные объекты а не объекты верхнего уровня в результате запроса и не могут быть указаны в другом месте по запросу.
И он также не поддерживается в запросах JPQL:
Ассоциация, на которую ссылается правая сторона предложения FETCH JOIN должна быть ассоциация или коллекция элементов, на которую ссылаются объект или вложенный, который возвращается в результате запроса.
Нельзя указывать идентификационную переменную для объекты, на которые ссылается правая сторона предложения FETCH JOIN, и поэтому ссылки на неявно получаемые объекты или элементы не могут появляются в другом месте запроса.
С HQL представляется возможным: Hibernate documentation EclipseLink не предоставляет такое расширение, поэтому синтаксис следующего запроса принимается Hibernate, но не EclipseLink:
SELECT a FROM A a LEFT JOIN FETCH a.bb b LEFT JOIN FETCH b.cc
В EclipseLink это можно сделать с помощью подсказок подсказок.