【问题标题】:Spring Data JPA Specification groupBySpring Data JPA 规范 groupBy
【发布时间】:2016-07-22 00:35:56
【问题描述】:

先对不起我的英语。

我想使用 jpa 来分组,例如:从数据流组中选择 scrip、dustup、count(*) by scrip、dstip。 所以,写下这些代码:

public class DataflowSpec {
    public static Specification<Dataflow> search(final String[] group, final String[] sort, final String[] desc) {
        return new Specification<Dataflow>() {
            @Override
            public Predicate toPredicate(Root<Dataflow> root1, CriteriaQuery<?> query1, CriteriaBuilder builder) {
                // TODO Auto-generated method stub

                CriteriaQuery<Tuple> query = builder.createQuery(Tuple.class);

                Root<Dataflow> root = query.from(Dataflow.class);


                query.multiselect(root.get("srcip"), root.get("dstip"), builder.count(root));

                query.groupBy(root.get("srcip"), root.get("dstip"));

                query.orderBy(builder.desc(root.get("srcip").as(BigInteger.class)));
                return query.getRestriction();
            }
        };
    }
}

但是,SQL 日志是: 休眠:

select
    count(dataflow0_.id) as col_0_0_ 
from
    Dataflow dataflow0_

休眠:

select
    dataflow0_.id as id1_2_,
    dataflow0_.byteall as byteall2_2_,
    dataflow0_.bytedn as bytedn3_2_,
    dataflow0_.byteup as byteup4_2_,
    dataflow0_.dstip as dstip5_2_,
    dataflow0_.dstport as dstport6_2_,
    dataflow0_.engieid as engieid7_2_,
    dataflow0_.flag as flag8_2_,
    dataflow0_.netid as netid9_2_,
    dataflow0_.pkgall as pkgall10_2_,
    dataflow0_.pkgdn as pkgdn11_2_,
    dataflow0_.pkgup as pkgup12_2_,
    dataflow0_.protocolid as protoco17_2_,
    dataflow0_.rtt as rtt13_2_,
    dataflow0_.srcip as srcip14_2_,
    dataflow0_.srcport as srcport15_2_,
    dataflow0_.updatetime as updatet16_2_ 
from
    Dataflow dataflow0_ limit ?

那么,如何解决呢?谢谢!

【问题讨论】:

  • 你用 JPQL 试过了吗?
  • 所以你将 WHERE 子句的谓词返回(到某处)...... SELECT 子句部分会发生什么?
  • 不,我只想使用规范。
  • 斯托克顿。我希望 SELECT 使用两个字段:srcip、dstip。但它返回所有字段。

标签: java spring hibernate jpa


【解决方案1】:

对于仍在寻找如何在 Spring jpa 规范中应用“分组依据”的人,您可以使用类似以下 sn-p 的内容:


...
private Dataflow dataflowFilter;

@Override
public Predicate toPredicate(Root&ltDataflow&gt root, CriteriaQuery&lt?&gt cq, CriteriaBuilder cb) {
    Predicate predicate = cb.conjunction();
    predicate.getExpressions().add(cb.equal(root.get("id"), dataflowFilter.getId()));
    ...
    cq.groupBy(root.get("id"));
    ...
    return predicate;
}

【讨论】:

    【解决方案2】:

    你可以通过specification实现spring数据group by,关注即可
    [2.6 节][1] 或 [3.6 节][2] 用于 2.0 之前或之后的版本。对于单个存储库操作,两个版本具有相同的解决方案。对于 *all * 存储库解决方案,在 2.0 之前使用 [customized factory bean][3],而在 2.0 之后省略此工厂 bean 操作。

    public Map<AlarmMsg.AlarmLevel, Long> testSpecification(String neId) {
    
        SingularAttribute attribute = AlarmData_.isClear;
        Specification<Object> where = Specification.where(
            (root, query, cb) -> cb.equal(root.get(attribute), false)
        );
    
        final Map<AlarmMsg.AlarmLevel, Long> result = alarmDataRepository.groupAndCount(AlarmData_.alarmLevel, where );
        return result;
    }
    

    存储库:

    public interface AlarmDataRepository extends JpaRepository<AlarmData, Long>, JpaSpecificationExecutor<AlarmData>, CustomizedGroupCountRepository {
    

    片段存储库及其实现:

    public interface CustomizedGroupCountRepository {
        Map<AlarmMsg.AlarmLevel, Long> groupAndCount(SingularAttribute singularAttribute, Specification where);
    }
    
    public class CustomizedGroupCountRepositoryImpl implements CustomizedGroupCountRepository {
        private final EntityManager entityManager;
    
    
        public CustomizedGroupCountRepositoryImpl(EntityManager entityManager) {
            Assert.notNull(entityManager, "EntityManager must not be null!");
            this.entityManager = entityManager;
        }
    
        @Override
        public Map<AlarmMsg.AlarmLevel, Long> groupAndCount(SingularAttribute singularAttribute, Specification where) {
            final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
            final CriteriaQuery<Tuple> query = criteriaBuilder.createQuery(Tuple.class);
            final Root<AlarmData> root = query.from(AlarmData.class);
            final Path<AlarmMsg.AlarmLevel> expression = root.get(singularAttribute);
            query.multiselect(expression, criteriaBuilder.count(root));
            query.select(criteriaBuilder.tuple(expression, criteriaBuilder.count(root)));
            query.where(where.toPredicate(root, query, criteriaBuilder));
            query.groupBy(expression);
            final List<Tuple> resultList = entityManager.createQuery(query).getResultList();
            return resultList.stream()
                .collect(toMap(
                    t -> t.get(0, AlarmMsg.AlarmLevel.class),
                    t -> t.get(1, Long.class))
                );
        }
    }
    

    one-for-all-repository 和 one-for-single-repository 的主要区别在于,在 one-for-single-repository 的情况下,它可以访问真实的实体类,如 spring 参考文档中的User .这样您就不需要使用泛型类型来引用任何类型的实体,而在one-for-all-repository 的情况下,自定义方法的实现使用泛型类型,其类信息可以(或必须)是如第 3.6 节所述,从注入的JpaEntityInformation 中获得。 [1]:https://docs.spring.io/spring-data/jpa/docs/1.8.0.RELEASE/reference/html/#repositories.single-repository-behaviour [2]:https://docs.spring.io/spring-data/jpa/docs/2.0.5.RELEASE/reference/html/#repositories.single-repository-behavior [3]:https://jeroenbellen.com/spring-data-extending-the-jpa-specification-executor/

    【讨论】:

      【解决方案3】:

      规范不支持 groupBy。 SimpleJpaRepository 将 query.select/multiselect 替换为 query.select(root)

      【讨论】:

      • Specification 用于where 部分。 CriteriaQuery 用于select
      猜你喜欢
      • 2016-02-17
      • 2017-01-12
      • 2019-05-25
      • 1970-01-01
      • 1970-01-01
      • 2012-08-15
      • 1970-01-01
      • 2020-03-01
      • 2017-10-28
      相关资源
      最近更新 更多