【问题标题】:How do I query based on fields of EmbeddedId using JPA Criteria?如何使用 JPA Criteria 基于 EmbeddedId 的字段进行查询?
【发布时间】:2020-03-01 04:47:16
【问题描述】:

我花了过去几个小时试图解决这个问题,主要是通过搜索,因为我认为 有人 已经这样做了,但我没有找到适合我的答案。

这是我的代码即时翻译成我可以公开的内容。

@Entity @Table(name="result")
public class Result implements Serializable {
    @Embeddable
    public static class ResultPK implements Serializable {
        @Column(name="result_date", nullable=false)
        @Type(type="com.example.HibernateUTC$LocalDateType") // <- UserType
        public LocalDate resultDate;
        @Column(name="name", nullable=false)
        public String name;
        @Column(name="category", nullable=false)
        public String category;
        public ResultPK() {}
        public ResultPK(Date resultDate, String name, String category) {
            this.resultDate = resultDate;
            this.name = name;
            this.category = category;
        }
        // ...more code for hashCode/equals, no setters or getters...
    }

    @EmbeddedId
    @AttributeOverrides({
            @AttributeOverride(name="resultDate", column=@Column(name="result_date", nullable = false)),
            @AttributeOverride(name="name", column=@Column(name="name", nullable=false)),
            @AttributeOverride(name="category", column=@Column(name="category", nullable = false)),
            })
    private ResultPK resultId;
    @Column(name="r_square")
    private Double rSq;
    @Column(name="p_value")
    private pValue;

    // ... more code for other fields, setters, getters, but nothing else; vanilla pojo...
}

我有一个隐藏查询的 DAO;我正在调用的方法是这样的

@Repository("resultDAO")
public class ResultDAOImpl extends AbstractBaseDAO<Result> implements ResultDAO {
    // boilerplate for intializing base class and other queries
    @Override
    public List<Result> findDateRange(String category, String name, LocalDate begDate, LocalDate endDate) {
        EntityManager em = entityManagerFactory.createEntityManager();
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Result> q = cb.createQuery(Result.class);
        Root<Result> root = q.from(Result.class);
        Predicate catMatch = cb.equal(root.get("resultId.category"), category);
        Predicate nameMatch = cb.equal(root.get("resultId.name"), name);
        Predicate dateRange = cb.between(root.get("resultId.resultDate"), begDate, endDate);
        q.select(root).where(cb.and(catMatch, nameMatch, dateRange));
        return em.createQuery(q).getResultList();
    }
}

当我尝试运行执行该查询的代码时,我会遇到错误

Exception in thread "main" java.lang.IllegalArgumentException: Unable to locate Attribute  with the the given name [resultId.category] on this ManagedType [com.example.Result]

我发现的一些类似问题使我看起来需要在查询中使用resultPKResultPK。我已经试过了,没有快乐。我不知道如何为查询指定键中的字段,或者我是否需要与此完全不同的东西。我真的需要一个线索...

我正在使用 Spring 4.3.8.RELEASE 和 Hibernate 4.3.11.Final,Java 8(因此使用 UserType 来处理 LocalDate)。

已编辑以纠正我在实际代码转录中的一些不一致之处。

【问题讨论】:

    标签: java criteria-api


    【解决方案1】:

    你应该这样修改你的谓词:

     Predicate catMatch = cb.equal(root.get("resultId").get("category"), category);
     Predicate nameMatch = cb.equal(root.get("resultId").get("name"), name);
     Predicate dateRange = cb.between(root.get("resultId").get("resultDate"), begDate, endDate);
    

    顺便说一下,在where 语句中不需要使用cb.and。您可以使用

    使代码更短一些
    q.select(root).where(catMatch, nameMatch, dateRange);
    

    【讨论】:

    • 完美!我敢肯定,既然我知道了答案,我会发现它已经在其他地方得到了回答,但是这在任何地方都很难找到。
    猜你喜欢
    • 2012-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-09
    • 1970-01-01
    • 2021-01-20
    • 1970-01-01
    相关资源
    最近更新 更多