2012-06-22 12 views
5

Kolega ma następujący (pozornie nieważnego) zapytania JPQL:W JPA 2.0 JPQL, gdy jeden zwraca NOWY obiekt, w jaki sposób można użyć powiązań FETCH?

SELECT NEW com.foobar.jpa.DonationAllocationDTOEntity(a.id, a.campaign, a.campAppeal, a.campDivision, a.divisionFund) 
FROM DonationAllocation a JOIN a.donation d JOIN a.allocationType t 
JOIN FETCH a.campaign 
WHERE d.id = :donationId 
AND (t.code = 'Pledge' OR t.code = 'MatchingPledge') 

Warto zauważyć (później w tej wiadomości), że związek DonationAllocation jest z jednostką Campaign jest wiele-do-jednego, i jest oznaczony jako FetchType.LAZY. Celem mojego kolegi w tym zapytaniu jest (między innymi) upewnienie się, że a.campaign jest "zawyżone" (niecierpliwie sprowadzone).

Hibernate (oczywiście tylko jeden wdrażanie WZP z kilku), w obliczu tego zapytania, mówi:

query specified join fetching, but the owner of the fetched association was not present in the select list

Ma to sens, jak select lista zawiera tylko NEW DonationAllocationDTOEntity() i sekcja 4.4.5.3 specyfikacji JPA 2.0 mówi:

Stowarzyszenie, do którego odnosi się prawa strona klauzuli PRZYŁĄCZ FETCH być skojarzeniem lub zbiorem elementów, do którego odwołuje się encja lub element możliwy do osadzenia, który jest zwracany w wyniku kwerendy.

tak, ponieważ nie ma żadnych „jednostka lub osadzone, który jest zwracany jako wynik zapytania” (to jest DTO wykonana za pomocą operatora NEW) wynika, że ​​nie jest możliwy związek do ładowania do pamięci Dołącz odwołać , a zatem zapytanie to jest nieprawidłowe.

W jaki sposób, biorąc pod uwagę to ograniczenie, należy skonstruować kwerendę JPQL w takim przypadku, aby a.campaign - w wyrażeniu konstruktora - było pobierane z niecierpliwością?

Odpowiedz

2

Chciałbym po prostu wybrać encję i jej powiązanie, a także llopover wyniki, aby explicitely wywołać konstruktora DTO. Można by mieć dodatkową zaletę kontroli czasu kompilacji i kod refactorable:

select a from DonationAllocation a 
JOIN a.donation d 
JOIN a.allocationType t 
JOIN FETCH a.campaign 
WHERE d.id = :donationId 
AND (t.code = 'Pledge' OR t.code = 'MatchingPledge') 

... 

for (DonationAllocation a : list) { 
    result.add(new DonationAllocationDTOEntity(a.id, 
               a.campaign, 
               a.campAppeal, 
               a.campDivision, 
               a.divisionFund)); 
} 

EDIT:

To zapytanie należy również zaznaczyć, co jest potrzebne i uniknąć wybierając całą jednostkę DonationAllocation:

select a.id, a.campaign, a.campAppeal, a.campDivision, a.divisionFund 
from DonationAllocation a 
JOIN a.donation d 
JOIN a.allocationType t 
WHERE d.id = :donationId 
AND (t.code = 'Pledge' OR t.code = 'MatchingPledge') 

i możesz po prostu dodać konstruktora DTO w zapytaniu, jeśli chcesz:

select new com.foobar.jpa.DonationAllocationDTOEntity(a.id, a.campaign, a.campAppeal, a.campDivision, a.divisionFund) 
from DonationAllocation a 
JOIN a.donation d 
JOIN a.allocationType t 
WHERE d.id = :donationId 
AND (t.code = 'Pledge' OR t.code = 'MatchingPledge') 

Fakt, że a.ampaign znajduje się w klauzuli select, powinien wystarczyć do powiadomienia Hibernate o załadowaniu encji. Tak przynajmniej zachowuje się w moich testach.

+0

Dziękuję. 'DonationAllocation' jest obecnie * wielkim * obiektem, ze zbyt wieloma relacjami" EAGER ". Wierzę, że mój kolega próbuje wycofać tylko niektóre jego części. Tak się składa, że ​​jedna z tych relacji, którą on * robi * faktycznie chce z zapałem załadować w tym zapytaniu. Czy dzięki tej nowej wiedzy zmienisz twoją odpowiedź? –

+0

Tak, zobacz moją odpowiedź. Ale jeśli ładowanie istoty jest takim problemem, oznacza to po prostu, że jej entuzjastyczne skojarzenia powinny być leniwe. Wolę robić wszystko leniwym. –

Powiązane problemy