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是多对一的,并被标记为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-- 传递到构造函数表达式 -- 被急切地获取?

4

1 回答 1

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 加载实体。至少在我的测试中它是这样的。

于 2012-06-22T21:57:44.483 回答