2013-02-07 17 views
1

我試圖使用Criteria Query API + RAD/Dali自動生成的用於OpenJPA 2.1的靜態規範元模型複製以下工作查詢在WebSphere v8.0.0.5 1,2-快照:JPA2 - 如何按OpenJPA中的嵌入式組合主鍵中的字段排序

`SELECT * 
FROM CENTER c 
    INNER JOIN STATE s ON s.ID = c.STATE_ID 
    INNER JOIN HOURS_OF_OPERATION h ON h.CENTER_ID = c.ID 
WHERE c.CITY = '<city_name_here>' 
ORDER BY h.WEEKDAY_NUMBER;` 

我有形成此查詢的核心四個實體:

  • Center.java
  • State.java
  • 侯rsOfOperation.java
  • HoursOfOperationPK.java

有每個國家的許多中心。每個中心有許多HoursOfOperations。我需要返回包含中心信息,狀態縮寫以及中心運行小時數的結果集,以星期一至星期日的星期幾1-7表示。

這裏是我的方法:

public Center getCenterInfo(String centerCityName) { 
    CriteriaBuilder cb = em.getCriteriaBuilder(); 

    CriteriaQuery<Center> cq = cb.createQuery(Center.class); 
    Metamodel m = em.getMetamodel(); 
    EntityType<Center> _center = m.entity(Center.class); 
    EntityType<State> _state = m.entity(State.class); 

    Root<Center> center = cq.from(_center); 
    Join<Center, State> state = center.join(Center_.state); 
    Join<Center, HoursOfOperation> hop = center.join(Center_.hoursOfOperations); 
    cq.select(center).distinct(true); 
    Predicate predicate = cb.equal(center.get(Center_.city), centerCityName); 
    cq.where(predicate); 
    //cq.orderBy(cb.asc(hop.get(HoursOfOperation_.id)));<---Can't access PK field here 
    center.fetch(Center_.state); 
    center.fetch(Center_.hoursOfOperations); 

    TypedQuery<Center> query = em.createQuery(cq); 
    Center centerInfo = query.getSingleResult(); 

    return centerInfo; 
} 

我註釋掉了我卡就行了。我想我必須調用一些方法來實例化某種HoursOfOperationPK實例,就像我使用Join<Center, HoursOfOperation> hop一樣。我認爲這樣做可以讓我使用類似cq.orderBy(cb.asc(hopPk.get(HoursOfOperationPK_.weekdayNumber)));的東西我該如何做到這一點?其次,如果我不使用cq.select(center).distinct(true);,我會取回49條記錄而不是7條記錄。這是爲什麼?將記錄倒數至7的唯一方法是附加到選擇的獨特方法。我理解DISTINCT在SQL中的作用,但是我的ANSI風格的SQL語法只返回7條記錄。

OpenJPA日誌輸出表明OrderBy應用於HoursOfOperation.centerId。

這裏的HoursOfOperation的相關部分和HoursOfOperationPK實體:

@Entity 
@Table(name="HOURS_OF_OPERATION") 
public class HoursOfOperation implements Serializable { 
    private static final long serialVersionUID = 1L; 

    @EmbeddedId 
    private HoursOfOperationPK id; 

    public HoursOfOperationPK getId() { 
     return this.id; 
    } 

    public void setId(HoursOfOperationPK id) { 
     this.id = id; 
    } 
} 

@Embeddable 
public class HoursOfOperationPK implements Serializable { 
    //default serial version id, required for serializable classes. 
    private static final long serialVersionUID = 1L; 

    @Column(name="CENTER_ID", unique=true, nullable=false) 
    private long centerId; 

    @Column(name="WEEKDAY_NUMBER", unique=true, nullable=false) 
    private long weekdayNumber; 

    public HoursOfOperationPK() { 
    } 
    public long getCenterId() { 
     return this.centerId; 
    } 
    public void setCenterId(long centerId) { 
     this.centerId = centerId; 
    } 
    public long getWeekdayNumber() { 
     return this.weekdayNumber; 
    } 
    public void setWeekdayNumber(long weekdayNumber) { 
     this.weekdayNumber = weekdayNumber; 
    } 
} 

編輯 @perissf我是能夠產生使用期望的結果SANS明確的順序由ASC(一種似乎隱含發生由於weekdayNumber是運營小時表的複合主鍵的一部分,我寧願有明確的排序,因爲它可以幫助我進行其他查詢,我可能不那麼幸運):

CriteriaBuilder cb = em.getCriteriaBuilder(); 

    CriteriaQuery<Center> cq = cb.createQuery(Center.class); 
    Metamodel m = em.getMetamodel(); 
    EntityType<Center> _center = m.entity(Center.class); 

    Root<Center> center = cq.from(_center); 
    Expression<List<HoursOfOperation>> hop = center.get(Center_.hoursOfOperations); 
    cq.select(center); 
    Predicate predicate = cb.equal(center.get(Center_.city), centerCityName); 
    cq.where(predicate); 

    center.fetch(Center_.state); 
    center.fetch(Center_.hoursOfOperations); 

    TypedQuery<Center> query = em.createQuery(cq); 
    Center centerInfo = query.getSingleResult(); 

但是,我能夠使用以下方式生成所需的SQL,但唯一的問題是中心的hoursOfOperation未設置(由於延遲加載。 A center.Fetch(Center_.hoursOfOperation)創建重複記錄。任何人都有解決方案?):

CriteriaBuilder cb = em.getCriteriaBuilder(); 
    CriteriaQuery<Center> cq = cb.createQuery(Center.class); 
    Metamodel m = em.getMetamodel(); 
    EntityType<Center> _center = m.entity(Center.class); 
    Root<Center> center = cq.from(_center); 
    EntityType<HoursOfOperation> _hoo = m.entity(HoursOfOperation.class); 
    Root<HoursOfOperation> hoo = cq.from(_hoo); 
    cq.select(center).distinct(true); 
    Predicate predicate = cb.and(cb.equal(center.get(Center_.city), centerCityName), 
      cb.equal(center, hoo.get(HoursOfOperation_.center))); 
    cq.where(predicate); 
    cq.orderBy(cb.asc(hoo.get(HoursOfOperation_.id).get(HoursOfOperationPK_.weekdayNumber))); 
    center.fetch(Center_.state); 

    TypedQuery<Center> query = em.createQuery(cq); 
    Center centerInfo = query.getSingleResult(); 
+0

我想出了WAS v8的trace.log文件的位置。我可以看到這些查詢。至少在正確的方向上取得了一些進展。 –

+0

O.K.取得了更多進展。我可以通過Path對象導航到HoursOfOperationPK: 'Path hopPk = hop.get(HoursOfOperation_.id); cq.orderBy(cb.asc(hopPk.get(HoursOfOperationPK_.weekdayNumber)));' 這會在生成的SQL中按兩個不同的HoursOfOperation別名的weekdayNumber和centerId字段進行排序。如果其中一個HoursOfOperation別名僅用於按星期幾編號進行排序,並且centerId排序被刪除,那麼更正問題的方法是什麼。我怎樣才能做到這一點? –

回答

1

我與的EclipseLink + MySQL的測試,並且可以證實,下面的代碼生成您正在尋找查詢:

Root<Center> center = cq.from(Center.class); 
Join<Center, HoursOfOperation> hoursOfOperation = center.join(Center_.hoursOfOperations); 
Join<Center, State> state = center.join(Center_.stateId); 
Path<HoursOfOperationPK> hoursOfOperationPK = hoursOfOperation.get(HoursOfOperation_.hoursOfOperationPK); 
cq.where(cb.equal(center.get(Center_.city), "cityName")); 
cq.orderBy(cb.asc(hoursOfOperationPK.get(HoursOfOperationPK_.weekdayNumber))); 
TypedQuery<Center> query = em.createQuery(cq); 

結果查詢:

SELECT t1.id, t1.city, t1.state_id 
FROM state t0, hours_of_operation t2, center t1 
WHERE ((t1.city = ?) AND ((t0.id = t1.state_id) AND (t2.center_id = t1.id))) 
ORDER BY t2.weekday_number ASC 

如果由此產生的行數與您期望的數量相比太多了,這是由於與State實體的連接造成的,該實體在Predicate之外沒有被過濾,所以得到的行是汽車這兩張桌子的西洋產品。

+0

你擊中了頭部。事實證明,我甚至不需要這兩個聯接中的任何一個。我現在只看到SELECT語句中列出的3個表。儘管如此,我還是回到了原點。我不知道現在如何排序。我無法將路徑更改爲:Path hop = center.get(Center_.hoursOfOperations);'然後繼續沿着路徑進入HoursOfOperationPK對象。 –

相關問題