2013-05-21 17 views
7

Nie sądzę, że kiedykolwiek w pełni zrozumiem pobieranie sprzężeń.Jak wykonać "głębokie" sprzężenie pobierania w JPQL?

Mam kwerendę, w której próbuję z niecierpliwością "napompować" referencje na dwóch poziomach.

Oznacza to, że mój A ma opcjonalnej Collection z B s, a każdy B ma wartość 0 lub 1 C. Wielkość kolekcji B jest znana jako mała (10-20 wierzchołków). Chciałbym wstępnie pobrać ten wykres. Powiązanie

A jest oznaczone jako FetchType.LAZY i jest opcjonalne. Związek B z C jest również opcjonalny i FetchType.LAZY.

Miałem nadzieję, mógłby zrobić:

SELECT a 
    FROM A a 
    LEFT JOIN FETCH a.bs // look, no alias; JPQL forbids it 
    LEFT JOIN a.bs b // "repeated" join necessary since you can't alias fetch joins 
    LEFT JOIN FETCH b.c // this doesn't seem to do anything 
WHERE a.id = :id 

Kiedy uruchamiam to, widzę, że A s B kolekcja jest rzeczywiście naciągane (widzę LEFT JOIN w SQL odwołuje się do stołu, do którego B jest odwzorowany) .

Nie widzę jednak takich dowodów na to, że tabela jest pobierana C.

Jak mogę wstępne pobieranie wszystkie C S i wszystkie B S i wszystkie C s, które są „osiągalny” z danego A? Nie widzę żadnego sposobu, aby to zrobić.

+1

Co dostawca JPA używacie? W EclipseLink dostępne są wskazówki dotyczące tego rodzaju funkcji. Zapoznaj się z podpowiedziami 'eclipselink.join-fetch' i' eclipselink.batch' ... – Cascader

+0

Dziękuję. Jeśli używam 'eclipselink.join-fetch', wygląda na to, że mogę ustawić tylko jeden atrybut. Czy to jest poprawne? Na przykład, jeśli zdmuchnę moją stolicę 'join-fetch' na' a.bs.c', to gdybym również chciał dołączyć do fetch-say-'a.bs.d, nie miałbym szczęścia. Dobrze? –

+0

To jest interesujące. Dokumentacja EclipseLink (http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Query_Hints#Join_Fetch) nie mówi, że duplikaty kluczy podpowiedzi do zapytania są możliwe, ale być może są? Zobacz ten interesujący link: https://github.com/mysema/querydsl/issues/348 –

Odpowiedz

5

WZP Spec nie pozwala aliasing jego pobrania dołączyć, ale niektórzy dostawcy JPA zrobić.

EclipseLink działa od wersji 2.4. EclipseLink pozwala również na pobieranie złącz zagnieżdżonych za pomocą notacji kropkowej (np. "JOIN FETCH a.bs.c") i obsługuje podpowiedź do zapytania "eclipselink.join-fetch", która umożliwia zagnieżdżone połączenia (możesz podać wiele wskazówek o tej samej nazwie podpowiedzi).

Generalnie należy zachować ostrożność podczas używania aliasu w łączeniu pobierania, ponieważ może to wpłynąć na zwrócone dane.

See, http://java-persistence-performance.blogspot.com/2012/04/objects-vs-data-and-filtering-join.html

+0

Dzięki, @ James; z różnych powodów musimy zachować nasz standard JPQL, więc wygląda na to, że wskazówki dotyczące łańcucha znaków są dla mnie. Warto zauważyć, że użycie kilku z nich powoduje błąd: https://bugs.eclipse.org/bugs/show_bug.cgi?id=408719 (również zgłoszony przez kogoś innego w 2010 roku tutaj: https://forums.oracle. com/forums/thread.jspa? threadID = 847970. Wciąż jestem zbytnio preteresowania zbyt głęboko, więc może to jest dziwne dla najlepszych. :-) –

+0

eclipselink.join-fetch działa również w eclipseLink 2.3: .setHint ("eclipselink.join-fetch", "a.bs.c") – tak3shi

4

JPA nie pozwala dołączyć pobieraniom zagnieżdżonych, ani pozwolić na alias przyłączyć sprowadzić, więc jest to prawdopodobnie JPA dostawca specyficzny.

W EclipseLink można określić wskazówkę dotyczącą kwerendy, aby wykonać zagnieżdżone dołączenia pobrań.

Nie można uczynić go rekursywnym w języku JPQL, ale można przejść tylko na najwyższych poziomach n na poziomie . W EclipseLink można użyć @JoinFetch lub @BatchFetch na mapowania, aby zapytanie było rekurencyjne.

See, http://java-persistence-performance.blogspot.com/2010/08/batch-fetching-optimizing-object-graph.html

Źródło: http://www.coderanch.com/t/570828/ORM/databases/Recursive-fetch-join-recursively-fetching

3

używam hibernacji (a to może być specyficzny dla niego) i miałem powodzenia z tym:

SELECT DISTINCT a, b 
FROM A a 
LEFT JOIN a.bs b 
LEFT JOIN FETCH a.bs 
LEFT JOIN FETCH b.c 
WHERE a.id = :id 

(Zauważ b w liście wyboru).

To był jedyny sposób znalazłem to będzie pracować dla mnie, to zwraca uwagę, że Object[] dla mnie i następnie filtrować je w kodzie tak:

(List<A>) q.getResultList().stream().map(pair -> (A) (((Object[])pair)[0])).distinct().collect(Collectors.toList()); 
Powiązane problemy