Как получить все данные одним запросом

У меня есть несколько объектов, которые запрашиваются через запрос критериев 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, что он должен выбирать все объекты сразу?


person Stinnux    schedule 15.12.2011    source источник


Ответы (2)


С помощью 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();

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

person Arjan Tijms    schedule 15.12.2011
comment
Он работает из-за расширений поставщика в некоторых реализациях (например, Hibernate). В JPA вообще этот запрос JPQL не работает, потому что такая цепочка и псевдонимы в этом случае не должны поддерживаться в соответствии со спецификацией. - person Mikko Maunu; 16.12.2011
comment
Спасибо за разъяснение, Микко. Довольно неприятно, что такие расширения активируются незаметно, поэтому вы используете их, даже не осознавая этого. - person Arjan Tijms; 16.12.2011
comment
Пока спасибо. Использование выборки без использования соединения до решает проблему. Однако я хотел бы поместить предикат в объединенную таблицу. как я мог это сделать? Раньше я использовал следующую конструкцию: Join ‹Object, Object› ladung = from.join (ladung); ladung.get (fzadresse) .in (адрес); - person Stinnux; 16.12.2011
comment
@Mikko, если это расширение поставщика, то почему API критериев возвращает экземпляр Fetch, для которого мы можем снова вызвать fetch ()? - person Mike Braun; 16.12.2011
comment
К сожалению, мне неизвестна мотивация этих дизайнерских решений. Возможно, они предпочли простоту интерфейса точности. - person Mikko Maunu; 17.12.2011
comment
Итак, fetch (...). Fetch () выдает что-то вроде unsupportedOperationException с использованием EclipseLink? - person Mike Braun; 17.12.2011
comment
Возможно, это даже работает, дело в том, что если оно работает, то оно работает из-за расширений функциональности поставщика постоянства. Реализации предоставляют множество дополнительных удобных вещей, что хорошо, по крайней мере, до тех пор, пока нет необходимости изменять реализацию. - person Mikko Maunu; 17.12.2011

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

На ассоциацию или атрибут, на который ссылается метод выборки, должна ссылаться сущность или встраиваемый объект, возвращаемый в результате запроса. Соединение выборки имеет ту же семантику соединения, что и соответствующее внутреннее или внешнее соединение, за исключением того, что связанные объекты не являются объектами верхнего уровня в результате запроса и не могут быть упомянуты в запросе где-либо еще.

И это также не поддерживается в запросах JPQL:

Ассоциация, на которую ссылается правая часть предложения FETCH JOIN, должна быть ассоциацией или коллекцией элементов, на которые ссылается объект или встраиваемый объект, возвращаемый в результате запроса.

Не разрешается указывать идентификационную переменную для объектов, на которые ссылается правая часть предложения FETCH JOIN, и, следовательно, ссылки на неявно выбранные сущности или элементы не могут появляться где-либо еще в запросе.

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

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

В EclipseLink то же самое можно сделать с помощью подсказок по запросу.

person Mikko Maunu    schedule 15.12.2011
comment
В HQL, как получить только некоторые столбцы a и некоторые столбцы a.bb? - person Ismail Yavuz; 20.12.2019