You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:04:22