zapytanie określiło pobieranie złączenia, ale właściciel pobranego powiązania nie był obecny na liście wyboru

83

Wybieram dwie kolumny identyfikatora, ale został określony błąd:

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=r,role=null,tableName=REVISIONS,tableAlias=revision1_,origin=ENTITY_CHANGED_IN_REVISION entitychan0_,columns={entitychan0_.REV_ID ,className=ru.csbi.registry.domain.envers.Revision}}] [ select ec.id as entityChangeId, r.id as revisionId from ru.csbi.registry.domain.envers.EntityChange as ec  inner join fetch ec.revision as r  where ec.groupEntityId = :groupEntityId and ec.groupName = :groupName  and r.timestamp < :entityDateFrom  and r.timestamp > :entityDateTo  and (        ec.revisionType in (0, 5, 1, 4, 2 )       and not ( ec.otherGroupEntityModified = false and ec.thisGroupEntityModified = true and ec.rowDataModified = false and ec.collectionOfNotGroupEntityModified = false   )      )  group by ec.id, r.id  having count(*) > :start order by r.id desc]

Jakiś kod:

String hql = " select ec.id as entityChangeId, r.id as revisionId from EntityChange as ec " +
            " inner join fetch ec.revision as r " +
            " where ec.groupEntityId = :groupEntityId" +
            " and ec.groupName = :groupName " +
            " and r.timestamp < :entityDateFrom " +
            " and r.timestamp > :entityDateTo " +
            " and ( " +
            "       ec.revisionType in (" + 
                        RevisionType.ADD.getRepresentation() + ", " + 
                        RevisionType.ONLY_DATA_PROPERTY_MOD.getRepresentation() + ", " +
                        RevisionType.BOTH_COLLECTION_AND_PROPERTY_MOD.getRepresentation() + ", " +
                        RevisionType.ONLY_COLLECTION_PROPERTY_MOD.getRepresentation() + ", " +
                        RevisionType.DEL.getRepresentation() +
                    " ) " +
            "     and not ( "+
                    "ec.otherGroupEntityModified = false and " +
                    "ec.thisGroupEntityModified = true and " +
                    "ec.rowDataModified = false and " +
                    "ec.collectionOfNotGroupEntityModified = false " +
                "  ) " +
            "     ) " +
            " group by ec.id, r.id " +
            " having count(*) > :start" +
            " order by r.id desc";

Jak naprawić błąd i co robię źle?

Wiaczesław
źródło
6
dla przyszłych poszukiwaczy tego pytania, w mojej sytuacji dołączyłem do nie leniwego atrybutu. Kiedy usunąłem klauzulę łączenia, zostało to rozwiązane.
merveotesi
2
Myślę, że w twoim przypadku problem polega na tym, że nie wybierasz całej encji (EntityChange), ale tylko kilka kolumn. Klauzula pobierania ma sens tylko wtedy, gdy wybrana jest jednostka główna i chcesz, aby zmapowana kolekcja / jednostka została wypełniona poprzez dołączenie do niej.
andy

Odpowiedzi:

118

Użyj zwykłego joinzamiast join fetch(nawiasem mówiąc, jest to innerdomyślne):

String hql = " select ec.id as entityChangeId, r.id as revisionId from EntityChange as ec " + 
        " join ec.revision as r " + ...

Jak mówi komunikat o błędzie, join fetchnie ma tu sensu, ponieważ jest to wskazówka dotycząca wydajności, która wymusza chętne ładowanie kolekcji.

axtavt
źródło
4
Dla wyjaśnienia, join fetchmoże być również używany do wymuszania gorliwego ładowania skojarzenia, takiego jak pole z adnotacją @ManyToOne, a nie tylko kolekcji.
Robert Hunt
52
Hm ... mam podobny problem, ale muszę wykonać pobieranie sprzężenia, aby uniknąć problemu n + 1
Zhenya
4
@levgen, nie znam szczegółów Twojego zapytania, ale pamiętaj, że zapytanie zliczające nie powinno w ogóle zawierać opcji „pobieranie”. codingexplained.com/coding/java/spring-framework/…
uśmiech
4
@levgen Trudno ci pomóc bez zobaczenia kodu, ale jeśli zdarzy się, że używasz Spring Data z @Queryadnotacją, możesz określić oddzielne zapytania do pobierania i liczenia: zobacz to pytanie (Spring-Data FETCH JOIN with Paging nie działa) dla szczegółów.
naXa
2
Usunięcie polecenia „fetch” doprowadziło mnie do problemu N + 1 i spowodowało zawieszenie się wszystkiego w mojej aplikacji. Nie polecałbym tego rozwiązania nikomu.
Alkis Mavridis
20

Ponieważ potrzebujesz dołączenia do pobierania, usunięcie pobierania nie spełni twoich potrzeb.

Zamiast tego powinieneś podać razem z nim zapytanie liczące.

Zakładając, że paginujesz wynik, poniżej znajduje się zapytanie jpa, które przyjmuje id jako parametr i spowoduje problem, który podałeś, a drugie zapytanie rozwiązuje go, dodając do niego zapytanie count.

Uwaga: fk_fieldto atrybut w tabeli A, który ma rln jeden do wielu. Zapytanie zliczające nie korzysta z pobierania sprzężenia.

@Query(value = "from TableA a LEFT JOIN FETCH a.fk_field where a.id = :id") 

@Query(value = "from TableA a LEFT JOIN FETCH a.fk_field where a.id = :id", 
  countQuery = " select  count(a) from TableA a left join a.fk_field where a.id = :id")
mój klucz
źródło