Использование @EntityGraph с выражениями конструктора JPA

#java #hibernate #jpa

#java #переход в спящий режим #jpa

Вопрос:

У меня есть запрос, который использует выражение конструктора. По большей части это работает, но я хотел уменьшить количество запросов к базе данных. Итак, я попробовал FETCH и @EntityGraph, но я получаю

org.springframework.dao.InvalidDataAccessResourceUsageException: запрос задал выборку соединения, но владелец выбранной ассоциации отсутствовал в списке выбора [fromElement{явный, не объединение коллекции, объединение выборки, извлечение не ленивый …

Я попытался удалить FETCH и просто использовать JOIN для устранения проблемы, но он не выполняет операцию выборки.

Разрешено ли это вообще или возможно с помощью Hibernate / JPA?

С точки зрения кода это выглядит примерно так

 @Query("select new example.BillingTargetAndStudent(bt,s) from Student s, BillingTarget bt where s.id = bt.targetID and bt.account.status = :accountStatus and bt.account.organization = :organization")
Stream<BillingTargetAndStudent> streamAllByOrganizationAndStatusForStudentList(Organization organization, AccountStatus accountStatus);
  

Что я хочу сделать, так это ПОЛУЧИТЬ bt.account в том же запросе вместе с s.user.attributes. Обойти bt.account это не так уж сложно, но s.user.attributes было бы невозможно с выражением конструктора, поскольку это коллекция

Ответ №1:

В итоге я использовал Stream<Object[]>, а select bt, s from ... затем создал конвертер, который изменяет Object[] для вызова выражения конструктора

 default Stream<BillingTargetAndStudent> streamAllByOrganizationAndStatusForStudentList(Organization organization, AccountStatus accountStatus) {

    return streamAllByOrganizationAndStatusForStudentList0(organization, accountStatus)
        .map(o -> new BillingTargetAndStudent((BillingTarget) o[0], (Student) o[1]));
}

@Query("select bt, s from Student s join fetch s.user u join fetch u.attributes, BillingTarget bt join fetch bt.account a where s.id = bt.targetID and bt.account.status = :accountStatus and bt.account.organization = :organization")
Stream<Object[]> streamAllByOrganizationAndStatusForStudentList0(Organization organization, AccountStatus accountStatus);
  

Я могу немного сократить запрос, вставив один @EntityGraph

 @EntityGraph("Student.forStudentList")
@Query("select bt, s from Student s, BillingTarget bt left join fetch bt.billingContractTargets bct join fetch bt.account a where s.id = bt.targetID and bt.account.status = :accountStatus and bt.account.organization = :organization")
Stream<Object[]> streamAllByOrganizationAndStatusForStudentList0(Organization organization, AccountStatus accountStatus);
  
 @NamedEntityGraph(
    name = "Student.forStudentList",
    attributeNodes = {
        @NamedAttributeNode("schedules"),
        @NamedAttributeNode(value = "user", subgraph = "user.attributes"),
    },
    subgraphs = {
        @NamedSubgraph(name = "user.attributes",
            attributeNodes = {@NamedAttributeNode("attributes")})
    }
)
  

Но я ограничен только одним, и он должен быть объектом для репозитория. Я не могу сказать

 @EntityGraph("BillingTarget.forStudentList")
@EntityGraph("Student.forStudentList")