5

我想使用 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关系时做类似的事情也会很棒(例如,"id.edition.number"

4

2 回答 2

6

问题是您对 JPA 路径使用的理解。JPA 手册说:

可以通过重用点 (.) 运算符进一步扩展其类型为可持久用户类的路径表达式。例如,c.capital.name 是一个嵌套路径表达式,它从 Capital 实体对象延续到其名称字段。仅当路径表达式的类型也是用户定义的可持久类时,才能进一步扩展路径表达式。点 (.) 运算符不能应用于简单类型(数字、布尔值、字符串、日期)的集合、映射和值。

在您的情况下,您使用了 id.edition.number,其中IdBrand (id) 不是用户可持久类。

解决方案是以这种方式构建路径表达式:root.get("id").get("edition.number");


为避免此类问题,您可以编写一个路径构建器,它基于javax.persistence.metamodel.Attribute.PersistentAttributeType将决定路径的构建方式。对于基本元素 - 使用 .get(),对于集合元素使用 .join()。

为了让您了解您的错误,您需要阅读有关 JPA 路径的更多信息。这是一本关于 JPA 路径的好手册

于 2012-04-16T13:39:39.880 回答
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));
    }
}
于 2012-04-15T11:26:47.370 回答