Как присоединиться к извлечению атрибута элемента в коллекции с помощью QueryDSL JPA - PullRequest
0 голосов
/ 28 мая 2020

Сущности, как показано ниже:

class A {
    Long id;

    @ManyToMany
    @JoinTable(name = "rel_a_b", joinColumns = @JoinColumn(name = "a_id"), inverseJoinColumns = @JoinColumn(name = "b_id"))
    Set<B> bSet;
}

class B {
    Long id;

    @ManyToMany(mappedBy = "bSet")
    Set<A> aSet;

    @ManyToMany
    @JoinTable(name = "rel_b_c", joinColumns = @JoinColumn(name = "b_id"), inverseJoinColumns = @JoinColumn(name = "c_id"))
    Set<C> cSet;
}

class C {
    Long id;

    @ManyToMany(mappedBy = "cSet")
    Set<B> bSet;
}

Мне нужно выбрать A сущности и присоединиться к выборке bSet и cSet в B сущности. Используя критерии JPA, коды, как показано ниже:

    final Fetch<A, B> bSetFetch = rootA.fetch("bSet", JoinType.LEFT);
    bSetFetch.fetch("cSet", JoinType.LEFT);

, работают отлично, но я не могу добиться этого с помощью QueryDSL. Я пробовал

    final QA a = QA.a;
    jpaQuery
    .from(a)
    .leftJoin(a.bSet, QB.b).fetchJoin()
    .leftJoin(QB.b.cSet).fetchJoin()
    .select(a)

, но выдает исключение, что

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=b,role=A.b,tableName=`b`,tableAlias=b4_,origin=a a2_,columns={a2_.id ,className=B}}] [select a
from A a
  left join fetch a.bSet as b
  left join fetch b.cSet]]

, если без fetchJoin(), результаты не включают bSet и cSet. Может ли кто-нибудь это решить?

1 Ответ

0 голосов
/ 29 мая 2020

Соединения выборки применяются правильно с точки зрения QueryDSL. Мы также можем наблюдать это по тому факту, что созданный запрос JPQL выглядит правильно.

Ограничение здесь состоит в том, что Hibernate разрешает FETCH JOINS только в том случае, если владелец ассоциации выборки проецируется в предложении select. cSet - это ассоциация на B, поэтому вам нужно будет спроецировать свои b или опустить соединение выборки для cSet. Например:

jpaQuery
    .from(a)
    .leftJoin(a.bSet, QB.b).fetchJoin()
    .leftJoin(QB.b.cSet).fetchJoin()
    .select(a, b)

Теперь это приведет к дублированию результатов для a из-за количества элементов bSet. Это всего лишь ограничение соединений выборки в Hibernate.

В качестве альтернативы, вы можете рассмотреть возможность указания графика выборки для запроса:

EntityGraph postGraph = em.getEntityGraph("post");
query.setHint("javax.persistence.fetchgraph", postGraph);

Для получения дополнительной информации об использовании EntityGraphs см. https://www.baeldung.com/jpa-entity-graph

...