2012-04-15 78 views
5

我想使用JPA CriteriaBuilder創建查詢,並且我想添加ORDER BY子句。這是我的實體:是否可以使用JPA和CriteriaBuilder組合鍵進行排序

@Entity 
@Table(name = "brands") 
public class Brand implements Serializable { 

    public enum OwnModeType { 
     OWNER, LICENCED 
    } 

    @EmbeddedId 
    private IdBrand id; 
    private String code; 
    //bunch of other properties 
} 

嵌入式類是:

@Embeddable 
public class IdBrand implements Serializable { 

    @ManyToOne 
    private Edition edition; 
    private String name; 
} 

而且我建設我的查詢方式是這樣的:

CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery<Brand> q = cb.createQuery(Brand.class).distinct(true); 
Root<Brand> root = q.from(Brand.class); 
if (f != null) { 
    f.addCriteria(cb, q, root); 
    f.addOrder(cb, q, root, sortCol, ascending); 
} 
return em.createQuery(q).getResultList(); 

,這裏是該函數調用:

public void addCriteria(CriteriaBuilder cb, CriteriaQuery<?> q, Root<Brand> r) { 
} 

public void addOrder(CriteriaBuilder cb, CriteriaQuery<?> q, Root<Brand> r, String sortCol, boolean ascending) { 
    if (ascending) { 
     q.orderBy(cb.asc(r.get(sortCol))); 
    } else { 
     q.orderBy(cb.desc(r.get(sortCol))); 
    } 
} 

如果我嘗試設置​​爲類似"id.name"我得到以下錯誤:

javax.ejb.EJBException: java.lang.IllegalArgumentException: Unable to resolve attribute [id.name] against path

任何想法如何,我可以做到嗎?我試着在網上搜索,但我無法找到有關此提示...也將是巨大的,如果我可以做一個類似的ORDER BY時,我有一個@ManyToOne關係(例如,"id.edition.number"

回答

5

問題是您的JPA路徑用法的理解。 JPA Manual說:

Path expression whose type is a persistable user class can be extended further by reusing the dot (.) operator. For example, c.capital.name is a nested path expression that continues from the Capital entity object to its name field. A path expression can be extended further only if its type is also a user defined persistable class. The dot (.) operator cannot be applied to collections, maps and values of simple types (number, boolean, string, date).

在你的情況,你所用id.edition.number,其中IdBrand(ID)是不是用戶持久化類。

爲了解決方案是建設路徑表達式是這樣的:root.get("id").get("edition.number");


爲了避免這樣的問題,你可以寫一個路徑生成器,它基於javax.persistence.metamodel.Attribute.PersistentAttributeType將決定路徑的構建方式。對於基本元素 - 使用.get(),對於集合元素使用.join()。

爲了瞭解您的錯誤,您需要閱讀有關JPA路徑的更多信息。 Here is a good manual on JPA paths

+0

是的,就是我在鏈接到的其他答案中所說的。 我覺得這真的很煩人,不明白爲什麼它不能自動工作。據你所知,如果我使用IdClass而不是EmbeddedId,會有同樣的問題嗎? – Kjir 2012-04-17 15:11:38

+0

好吧,如果我們看[JPA類型層次結構](http://www.objectdb.com/java/jpa/persistence/metamodel#Type_Interface_Hierarchy_),我們可以看到,EntityType擴展了IdentifiableType,所以也許@Id(@IdClass )是可識別的類型,所以你可以做到這一點。你應該嘗試一下。同時從屬性獲取PersistentType,然後你可以定義你可以用它做什麼。 – JMelnik 2012-04-20 10:03:18

+0

正如我所說,**也許**這是可能的,所以你最好檢查一下PersistentType,並在這裏提供它,如果你可以請。 – JMelnik 2012-04-20 14:58:08

1

其實,我找到了答案另一個類似的問題:JPA - Criteria API and EmbeddedId

這是我如何固定我的代碼:

public void addOrder(CriteriaBuilder cb, CriteriaQuery<?> q, Root<Brand> r, String sortCol, boolean ascending) { 
    Path<?> p = r; 
    String []sortCols = sortCol.split("\\."); // This is a regexp, hence the escape backslash 
    for(String sc: sortCols) { 
     p = p.get(sc); 
    } 
    if (ascending) { 
     q.orderBy(cb.asc(p)); 
    } else { 
     q.orderBy(cb.desc(p)); 
    } 
} 
相關問題