【问题标题】:How to use javax.persistence.criteria.Predicate with complex types?如何将 javax.persistence.criteria.Predicate 与复杂类型一起使用?
【发布时间】:2016-03-29 09:19:40
【问题描述】:

我有一个覆盖方法“toPredicate”的方法:

@Override
public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
    List<Predicate> predicates = new ArrayList<>();

我必须构建谓词。 使用简单类型很容易,例如:

@Entity
@Table
public class Person {

    @Column
    private String name;

    @Column
    private String surname;

}

通过这个简单的课程我可以做到:

@Override
public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
    List<Predicate> predicates = new ArrayList<>();

    if (StringUtils.isNotBlank(surname)) {
        predicates.add(cb.equal(root.get("surname"), surname));
    }

    if (StringUtils.isNotBlank(name)) {
        predicates.add(cb.equal(root.get("name"), name));
    }

但是如果属性是复杂类型,如何找到复杂类型中包含的简单属性呢?

这是一种潜在的情况:

@Entity
@Table
public class Person {

    @Column
    private String name;

    @Column
    private String surname;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private List<Document> documents;

}

@Entity
@Table
public class Document {

    @Column
    private String type;

    @Column
    private String code;

}

如果我想用复杂的属性“documents”做一个谓词,我该怎么办?

我试过了:

@Override
public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
    List<Predicate> predicates = new ArrayList<>();

    if (StringUtils.isNotBlank(type)) {
        predicates.add(cb.equal(root.get("documents").get("type"), type));
    }

但我有这个例外:

java.lang.IllegalStateException: Illegal attempt to dereference path source [null.documents] of basic type
    at org.hibernate.jpa.criteria.path.AbstractPathImpl.illegalDereference(AbstractPathImpl.java:98)
    at org.hibernate.jpa.criteria.path.AbstractPathImpl.get(AbstractPathImpl.java:191)

我的任务是找到具有确定类型文档的每个人。 我该怎么做?

谢谢。

【问题讨论】:

    标签: java spring-data spring-data-jpa spring-data-rest javax.persistence


    【解决方案1】:

    你可以使用join:

    @Override
    public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
        Predicate predicate = null;
    
        if (StringUtils.isNotBlank(type)) {
            predicate = cb.equal(root.join("documents").get("type"), type);
    
           cq.where(predicate);
           cq.distinct(true);
    
          }
    

    【讨论】:

    • 好的,谢谢你的建议。它似乎有效,但仍然存在问题。如果我做: predicates.add(cb.equal(root.join("documents").get("type"), type));它返回具有某种类型的所有文档,因此我可以为 Person 类获得重复的结果。一个例子:“Jack”人有三个文档,其中 2 个有 type = “Paper”。通过这个实现,我有 2 条“Person”类型的记录(都是“Jack”)
    • cq.distinct(true);似乎足够了, cq.select(root) 给我一个编译错误。不过,感谢您的帮助!
    • @RafikBELDI 如果我需要选择文档属性怎么办?我认为加入不会自动选择 *.documents。
    猜你喜欢
    • 2018-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 2021-02-23
    • 1970-01-01
    • 2017-06-12
    相关资源
    最近更新 更多