2012-06-22 4 views
5

Ein Kollege von mir die folgenden (scheinbar ungültig) JPQL Abfrage hat: (in dieser Nachricht für später)In JPA 2.0 JPQL, wenn man ein neues Objekt zurückgibt, wie kann man FETCH JOINs nutzen?

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') 

Es ist erwähnenswert, dass mit einer Campaign Einheit DonationAllocation ‚s Beziehung viele-zu-eins ist, und ist als FetchType.LAZY markiert. Mit dieser Abfrage will mein Kollege unter anderem sicherstellen, dass a.campaign "aufgeblasen" wird (eifrig abgerufen).

Hibernate (natürlich nur eine JPA-Implementierung mehrerer), wenn sie mit dieser Abfrage konfrontiert, sagt:

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

Dies macht Sinn, da die Auswahlliste nur NEW DonationAllocationDTOEntity() enthält, und Abschnitt 4.4.5.3 der JPA 2.0 Spezifikation sagt:

Die Assoziation referenziert durch die rechte Seite der FETCH JOIN-Klausel muss Eine Assoziation oder Elementsammlung sein, auf die von einer Entität oder einer eingebetteten Entität verwiesen wird, die als Ergebnis der Abfrage zurückgegeben wird.

So, da es keine „Organisation oder integrierbare, die als Ergebnis der Abfrage zurückgegeben wird“ (es ist ein DTO konstruiert mit dem NEW Operator), folgt daraus, dass es keine mögliche Verbindung ist für ein FETCH JOIN zu referenzieren und daher ist diese Abfrage ungültig.

Wie, angesichts dieser Einschränkung, sollte man in diesem Fall eine JPQL-Abfrage konstruieren, so dass a.campaign - in den Konstruktor-Ausdruck übergeben - eifrig abgerufen wird?

Antwort

2

Ich würde einfach die Entität und ihre Zuordnung auswählen, und lopover die Ergebnisse, um den DTO-Konstruktor explizit aufzurufen. Sie würden den zusätzlichen Vorteil der Compile-Zeit überprüft und refactorable Code haben:

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:

Diese Abfrage sollte auch wählen, was nötig ist, und vermeiden Sie die ganze DonationAllocation Einheit Auswahl:

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') 

und Sie könnten nur den DTO-Konstruktor in der Abfrage hinzufügen, wenn Sie möchten:

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') 

Die Tatsache, dass sich die a.campaign in der select-Klausel befindet, sollte ausreichen, um Hibernate mitzuteilen, dass die Entity geladen werden soll. Zumindest verhält es sich so in meinen Tests.

+0

Vielen Dank. 'DonationAllocation' ist derzeit ein * riesiges * Objekt mit viel zu vielen' EAGER'-Beziehungen. Ich glaube, mein Kollege versucht nur bestimmte Teile davon zurückzuziehen. Es ist einfach so, dass eine dieser Beziehungen, die er * wirklich will, in dieser Frage eifrig geladen werden soll. Mit diesem neuen Wissen, würde das deine Antwort ändern? –

+0

Ja, sehe meine Antwort. Aber wenn das Laden der Entität ein solches Problem ist, bedeutet es nur, dass seine begierigen Assoziationen faul gemacht werden sollten. Ich ziehe es vor, alles faul zu machen. –

Verwandte Themen