2016-11-18 70 views
3

在我的項目上,我使用Groovy和Spring Data JPA的Specification來構建Hibernate查詢。使用JPA標準,我如何獲取未加入實體的連接實體的子實體?

我不能提供我的實際查詢,但爲了說明我的問題讓我們說我有建築實體,每個建築物都有樓層,每個樓層都有房間和Windows。

我試圖模仿行爲是這樣的原生SQL查詢:

SELECT b.*, r.* 
FROM building b 
INNER JOIN floor f ON b.id = f.building_id 
INNER JOIN window w ON f.id = w.floor_id 
LEFT OUTER JOIN room r ON f.id = r.floor_id 
WHERE w.id = 1; 

我有類似以下規範:

public class MySpec implements Specification<Building> { 
    @Override 
    public Predicate toPredicate(final Root<Building> root, final CriteriaQuery<?> query, final CriteriaBuilder cb) { 
     final Join floorsJoin = root.join("floors"); 
     final Join windowsJoin = floorsJoin.join("windows"); 

     //I'd like to remove this line 
     final Fetch floorsFetch = root.fetch("floors"); // <--- 

     floorsFetch.fetch("rooms", JoinType.LEFT); 

     cb.equal(windowsJoin.get("id"), 1L); 
    } 
} 

標註出來的線是我的問題。如果我離開它,生成的查詢看起來是這樣的:

SELECT b.*, f2.*, r.* 
FROM building b 
INNER JOIN floor f ON b.id = f.building_id 
INNER JOIN window w ON f.id = w.floor_id 
INNER JOIN floor f2 ON b.id = f2.building_id 
LEFT OUTER JOIN room r ON f2.id = r.floor_id 
WHERE w.id = 1; 

(注意的floor重複INNER JOIN和不必要的f2.*數據)

如果我刪除它,並使用floorsJoin,而不是獲取客房,我得到以下休眠錯誤:

org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list 

的不需要的f2.*數據將是美好的,除了我不能與T代替上面floorsJoinfloorsFetch,因爲我需要加入windows表(不提取windows)和Fetch類沒有.join方法。

我很難搞清楚如何完成我所需要的工作,同時仍然生成單個查詢;當然,我一定會錯過簡單的東西。

任何想法或建議,你可以提供將不勝感激。

非常感謝, B.J.

回答

0

那麼它不是與JPA標準API這麼簡單。使用Hibernate,你可以簡單地將Fetch轉換爲Join,但我認爲這不會對你有太大的幫助。我不確定你在這種情況下如何使用規範,但是如果你可以將整個查詢寫成整體,它可能看起來像下面這樣:

CriteriaBuilder cb = entityManager.getCriteriaBuilder(); 
CriteriaQuery<Tuple> cq = cb.createTupleQuery(); 

Root<Building> root = cq.from(Building.class); 
final Join floorsJoin = root.join("floors"); 
final Join windowsJoin = floorsJoin.join("windows"); 
final Join roomsJoin = floorsJoin.join("rooms", JoinType.LEFT); 

cb.equal(windowsJoin.get("id"), 1L); 

cq.multiselect(
    root, 
    roomsJoin 
);