5

私の同僚は、次の (明らかに無効な) JPQL クエリを持っています。

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

DonationAllocationとエンティティとの関係Campaignは多対 1 であり、 としてマークされていることに注意してください (このメッセージの後半で説明します) FetchType.LAZY。このクエリに対する私の同僚の意図は、(とりわけ)a.campaign「インフレ」(熱心にフェッチされる)であることを確認することです。

Hibernate (明らかに、いくつかの JPA 実装の 1 つにすぎません) は、このクエリに直面すると、次のように述べています。

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

NEW DonationAllocationDTOEntity()選択リストには のみが含まれており、JPA 2.0 仕様のセクション 4.4.5.3 には次のように記載されているため、これは理にかなっています。

FETCH JOIN 句の右側で参照される関連付けは、クエリの結果として返されるエンティティまたは埋め込み可能オブジェクトから参照される関連付けまたは要素のコレクションである必要があります。

したがって、「クエリの結果として返されるエンティティまたは埋め込み可能」(NEW演算子を使用して構築された DTO です) がないため、FETCH JOIN が参照する可能性のある関連付けがないため、このクエリは無効です。 .

この制限が与えられた場合a.campaign、コンストラクター式に渡されて熱心にフェッチされるように、この場合、どのように JPQL クエリを作成する必要がありますか?

4

1 に答える 1

2

単純にエンティティとその関連付けを選択し、結果を llopover して DTO コンストラクターを明示的に呼び出します。コンパイル時のチェックとリファクタリング可能なコードの追加の利点があります。

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));
}

編集:

このクエリでは、必要なものも選択し、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')

必要に応じて、クエリに DTO コンストラクターを追加することもできます。

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

a.campaign が select 句にあるという事実は、Hibernate にエンティティをロードするように指示するのに十分なはずです。少なくとも、それが私のテストでの動作です。

于 2012-06-22T21:57:44.483 に答える