我的一位同事有以下(显然无效)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
实体的关系是多对一的,并标记为FetchType.LAZY
。我的同事对此查询的意图是(除其他事项外)确保a.campaign
“膨胀”(急切地获取)。
Hibernate(显然只是一个JPA实现的几个),当遇到这个查询时,说:
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与之无关联。引用,因此该查询无效。
在给定此限制的情况下,如果在这种情况下构造一个JPQL查询,以便传递给构造函数表达式的a.campaign
- 是如何急切地获取的?
答案 0 :(得分:2)
我只需选择实体及其关联,然后重复结果以明确地调用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加载实体。至少这是我在测试中的表现。