【问题标题】:Is it possible to order by a composite key with JPA and CriteriaBuilder是否可以通过 JPA 和 CriteriaBuilder 的复合键进行排序
【发布时间】:2012-04-27 00:39:00
【问题描述】:

我想使用 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: Unable to resolve attribute [id.name] against path

知道我该如何做到这一点吗?我尝试在线搜索,但找不到关于此的提示...如果我有 @ManyToOne 关系(例如,"id.edition.number")时可以做类似的 ORDER BY 也很棒

【问题讨论】:

    标签: java jpa criteria-api


    【解决方案1】:

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

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

    在您的情况下,您使用了 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.

    【讨论】:

    • 是的,这就是我链接到的另一个答案中所说的。我觉得这真的很烦人,不明白为什么它不能自动工作。据您所知,如果我使用 IdClass 而不是 EmbeddedId,我会遇到同样的问题吗?
    • 好吧,如果我们查看JPA Type Hierarchy,我们可以看到,EntityType 扩展了 IdentifiableType,所以可能@Id (@IdClass) 是可识别类型,所以你可以这样做。你应该试试看。也可以从属性中获取 PersistentType,然后你可以定义你可以用它做什么。
    • 正如我所说,也许这是可能的,所以你最好检查一下 PersistentType,如果可以的话,请在此处提供。
    【解决方案2】:

    其实我找到了另一个类似问题的答案: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));
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-19
      • 1970-01-01
      • 2013-05-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多