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

如何在Spring Data中通过JPQL或Criteria Api按枚举属性分组获取自定义数据

没问题,我来帮你搞定这个按枚举分组的需求!针对你的Currency枚举和Sales实体,下面分别用JPQL和Criteria API两种方式实现,都是Spring Data JPA里常用的方案:


用JPQL实现按枚举分组

首先咱们得先准备一个DTO(数据传输对象),用来接收分组后的自定义结果——毕竟原生的Sales实体不符合咱们分组统计的需求:

public class SalesGroupByCurrency {
    private Currency currency;
    private Double totalAmount; // 该货币的总销售额
    private Long salesCount;    // 该货币的销售记录数

    // 注意:构造函数的参数顺序要和JPQL查询里SELECT的字段顺序完全一致
    public SalesGroupByCurrency(Currency currency, Double totalAmount, Long salesCount) {
        this.currency = currency;
        this.totalAmount = totalAmount;
        this.salesCount = salesCount;
    }

    // 按需添加getter方法,方便后续获取数据
    public Currency getCurrency() { return currency; }
    public Double getTotalAmount() { return totalAmount; }
    public Long getSalesCount() { return salesCount; }
}

接下来在你的SalesRepository里添加JPQL查询方法,直接按枚举属性分组:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;

public interface SalesRepository extends JpaRepository<Sales, Long> {

    @Query("SELECT new com.yourpackage.SalesGroupByCurrency(s.currency, SUM(s.amount), COUNT(s.id)) " +
           "FROM Sales s " +
           "GROUP BY s.currency")
    List<SalesGroupByCurrency> groupSalesByCurrency();
}

这里的关键点:

  • 用new关键字直接调用DTO的构造函数,把分组后的统计结果封装进去
  • GROUP BY s.currency直接使用枚举属性,JPA会自动处理枚举与数据库字段的映射(不管你数据库存的是枚举字符串还是序号,只要枚举配置正确就没问题)

用Criteria API实现按枚举分组

如果你的分组逻辑需要动态调整(比如后续要加过滤条件),用Criteria API会更灵活。同样需要用到上面的SalesGroupByCurrency DTO,然后按以下步骤实现:

1. 定义自定义Repository接口

先创建一个扩展接口,用来存放自定义的分组方法:

public interface SalesCustomRepository {
    List<SalesGroupByCurrency> groupSalesByCurrency();
}

2. 实现自定义Repository

编写实现类,用CriteriaBuilder构建查询:

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import java.util.List;

public class SalesCustomRepositoryImpl implements SalesCustomRepository {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public List<SalesGroupByCurrency> groupSalesByCurrency() {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<SalesGroupByCurrency> query = cb.createQuery(SalesGroupByCurrency.class);
        Root<Sales> root = query.from(Sales.class);

        // 构建查询结果:调用DTO构造函数,传入分组字段和统计函数
        query.select(cb.construct(SalesGroupByCurrency.class,
                root.get("currency"),
                cb.sum(root.get("amount")),
                cb.count(root.get("id"))))
             .groupBy(root.get("currency")); // 按枚举属性分组

        return entityManager.createQuery(query).getResultList();
    }
}

3. 让主Repository继承自定义接口

最后把自定义接口整合到主Repository里:

public interface SalesRepository extends JpaRepository<Sales, Long>, SalesCustomRepository {
}

小提示

  • 如果你的枚举在数据库中存储的是序号,记得在Sales实体的currency字段上添加@Enumerated(EnumType.ORDINAL)注解;如果存的是字符串(比如USD),用@Enumerated(EnumType.STRING)即可(默认也是STRING,可省略)
  • DTO的构造函数必须是public的,否则JPA无法实例化它

内容的提问来源于stack exchange,提问作者Samet Baskıcı

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:35:08