Spring Data JPA Specification如何比较日期列的年份?
使用JPA Specification实现按创建年份查询Ticket记录
问题描述
我原本通过JPA Repository的@Query注解实现了查询指定年份创建的Ticket记录的功能,代码如下:
@Query("select t from Ticket t where year(t.createDate) = ?1") List<Ticket> findByYearAndSort(int year, Sort sort);
这个方法可以正常工作,但当我尝试改用JPA Specification实现相同逻辑时,却遇到了异常:
static Specification<Ticket> createdIn(int year) { return (root, query, cb) -> cb.equal(root.get("year(createDate)"), year); }
抛出的异常信息:
InvalidDataAccessApiUsageException: Unable to locate Attribute with the the given name [year(createDate)] on this ManagedType [onlineTicket.utility.domain.Ticket]; nested exception is java.lang.IllegalArgumentException: Unable to locate Attribute with the the given name [year(createDate)] on this ManagedType [onlineTicket.utility.domain.Ticket]
我的Ticket实体类中createDate是LocalDate类型,对应数据库的create_date列,该字段本身没有问题,因为之前的findByYearAndSort方法能正常运行。
原因分析
你错误地将JPQL中的year(t.createDate)表达式直接当作实体的属性名称来获取,而year(...)是JPQL的函数调用,并不是实体的属性,所以JPA无法找到对应的属性,从而抛出异常。
正确解决方案
要在JPA Specification中调用数据库函数(比如YEAR),需要使用CriteriaBuilder的function方法来构建函数调用逻辑,修改后的代码如下:
static Specification<Ticket> createdIn(int year) { return (root, query, builder) -> builder.equal( builder.function("YEAR", Integer.class, root.get("createDate")), year); }
代码解释:
builder.function("YEAR", Integer.class, root.get("createDate")):通过function方法调用数据库的YEAR函数,第一个参数是函数名,第二个参数是函数返回值的类型,第三个参数是函数的输入参数(这里是Ticket实体的createDate属性)。builder.equal(...):将函数返回的年份值和传入的year参数进行相等判断,实现和原@Query注解完全一致的查询逻辑。
内容的提问来源于stack exchange,提问作者len
相关产品推荐
相关产品推荐

