我想使用JPA CriteriaBuilder创建一个查询,我想添加一个ORDER BY
子句。这是我的实体:
@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)));
}
}
如果我尝试将sortCol
设置为"id.name"
,我会收到以下错误:
javax.ejb.EJBException:java.lang.IllegalArgumentException:无法解析路径
的属性[id.name]
知道我怎么能做到这一点?我尝试在网上搜索,但是我找不到关于这一点的提示...如果我在ORDER BY
关系时可以做类似@ManyToOne
的话也会很棒(例如{{1} }})
答案 0 :(得分:5)
问题是您对JPA路径使用情况的理解。 JPA Manual说:
可以扩展其类型是可持久用户类的路径表达式 进一步重复使用点(。)运算符。例如,c.capital.name 是一个从Capital实体继续的嵌套路径表达式 对象到其名称字段。 可以进一步扩展路径表达式 仅当其类型也是用户定义的可持久类时。点(。) operator不能应用于简单的集合,映射和值 类型(数字,布尔值,字符串,日期)。
在您的情况下,您使用了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
答案 1 :(得分: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));
}
}