如何在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ı
相关产品推荐
相关产品推荐

