2012-02-17 78 views
4

從連接表中選擇對象我正在爲下面的問題爭取兩天時間,並希望您能夠推動我朝着正確的方向前進。我在研究中發現的教程和示例總是隻顯示瞭如何輕鬆加入標準api。首先我有兩個類:使用JPA Criteria-API

@Entity 
public class Offer { 

    private String name; 
    @ManyToOne private Location location; 
    private String tags; 
} 

@Entity 
public class Location { 
    private String name; 
    private string tags; 
} 

因爲我需要避免循環引用beween這些類的連接僅僅是單向的。在這個類中有很多附加屬性,我想根據我的搜索過濾器來構建動態查詢。下面的SQL語句將解釋什麼,我喜歡做的事:

SELECT l 
FROM Offer o 
JOIN o.location l 
WHERE o.tags LIKE :sometag AND l.tags LIKE :someothertag 

與標準的API,我得到這個代碼實現之後:

CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); 
CriteriaQuery<Location> criteriaQuery = criteriaBuilder.createQuery(Location.class); 
criteriaQuery = criteriaQuery.distinct(true); 
Join location; 
ArrayList<Predicate> whereList = new ArrayList<Predicate>(); 

// if filter by offer, use offer as main table and join location table 
if (filter.getOfferTags() != null) { 
    Root<Offer> offer = criteriaQuery.from(Offer.class); 

    location = offer.join("location"); 


    // limit to offering tags 
    Path<String> tagPath = offer.get("tags"); 

    for (String tag : filter.getOfferTags()) { 
    Predicate whereTag = criteriaBuilder.like(tagPath, "%" + tag + "%"); 
    whereList.add(whereTag); 
    } 

} else { 
    // else use location table as base 
    location = (Join<Location, Location>) criteriaQuery.from(Location.class); 
} 

但如果我執行此我收到以下錯誤信息從我的H2數據庫:

Column "LOCATION.ID" not found; SQL statement: 
SELECT DISTINCT LOCATION.ID, LOCATION.NAME 
FROM OFFER t0, LOCATION t1 
WHERE t0.TAGS LIKE ? AND t1.TAGS LIKE ? 

數據庫預計t1.ID和SELECT子句中t1.NAME而不是LOCATION.IDLOCATION.NAME。我如何告訴JPA創建「正確」請求?我在代碼中丟失了什麼嗎?

我使用Glassfish 3.1.1與Eclipse Link和H2數據庫。

回答

6

我認爲你只是錯過在查詢一個選擇:

criteriaQuery.select(location); 
+0

非常感謝。現在它可以工作。 – Ralph 2012-02-17 15:30:16

4

我不認爲你需要顯式指定在查詢中加入 - 畢竟報價已經有一個映射位置。

像這樣的東西就足夠了:

CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery<Location> cq = criteriaBuilder.createQuery(Location.class); 
Root<Offer> offer = criteriaQuery.from(Offer.class); 
cq.select(offer.get("location")); 
cq.where(...)