【问题标题】:Spring boot jpa query builder for aggregate values?用于聚合值的 Spring Boot jpa 查询构建器?
【发布时间】:2019-10-04 21:32:38
【问题描述】:

我想创建可自定义的查询来输出聚合值。我知道三种获取和执行查询的方法,但似乎都不够。我要构建的查询如下所示:

Select max(category), min(price) as minprice from mytable where k='v' group by category

tldr:跳过 1 和 2。

  1. SQL 作为字符串
    • private NamedParameterJdbcTemplate template; template.query("select ..." , new MapSqlParameterSource("...", "...") , rs -> {...rs.getString("minprice")...
    • 专业人士:我们可以访问查询的结果
    • 缺点:它没有使用查询构建器:我们必须自己构建“选择...”字符串。
  2. 使用存储库
    • public interface MytableRepository extends CrudRepository<Mytable, Integer> { @Query("Select ...") public List<Object[]> findMinMaxPrice(@Param("myParam") String myParam);
    • 专业人士:我们可以访问查询的结果。
    • 缺点:查询是硬编码的
  3. 使用查询生成器
    • Specification<MyTable> spec = Specifications.<>where((mytable, query, cb) -> { Predicate sql = cb.equal(mytable.get("k"), "v"; return sql; } List<Mytable> result = myJpaSpecificationExecutor.findall(spec);
    • Pro:它正在使用查询生成器
    • Con:查询未使用 groupBy。由于我们的 groupBy 查询不返回类 Mytable 的记录,而是返回聚合值,所以我不知道如何使这项工作。我从Mytable 开始选择,所以我认为我需要将它用作Specification 的类型参数,但这立即意味着结果也应该是MyTable 类型,不是吗?

如何使用具有灵活结果类型的查询生成器?

【问题讨论】:

    标签: java spring-boot spring-boot-jpa


    【解决方案1】:

    您可能会考虑查看 jOOQ,它可以为您提供尽可能多的灵活性,同时将您的查询保持在“代码中”,可以这么说。

    它可以从您的数据库模式生成 Java 类,您可以使用这些类通过其 DSL 形成查询。这是一个例子:https://github.com/benjamin-bader/droptools/blob/master/droptools-example/src/main/java/com/bendb/example/resources/PostsResource.java#L99

    这是我上面链接的代码的主要内容:

        final Record4<Integer, String, OffsetDateTime, String[]> record = create
                .select(BLOG_POST.ID, BLOG_POST.BODY, BLOG_POST.CREATED_AT, arrayAgg(POST_TAG.TAG_NAME))
                .from(BLOG_POST)
                .leftOuterJoin(POST_TAG)
                .on(BLOG_POST.ID.equal(POST_TAG.POST_ID))
                .where(BLOG_POST.ID.equal(id.get()))
                .groupBy(BLOG_POST.ID, BLOG_POST.BODY, BLOG_POST.CREATED_AT)
                .fetchOne();
    

    它看起来有点时髦,但它会生成以下内容:

    SELECT blog_post.id, blog_post.body, blog_post.created_at, array_agg(post_tag.tags)
    FROM blog_post
    LEFT JOIN post_tag ON blog_post.id = post_tag.post_id
    WHERE blog_post.id = ?
    GROUP BY blog_post.id, blog_post.body, blog_post.created_at
    

    您可以看到 Java 代码与生成的 SQL 非常相似,但是由于 jOOQ 的生成代码,它仍然是完美的类型安全的。因为它是代码,所以您可以根据需要动态构建查询。

    这是一个沉重的依赖,但如果您的 SQL 需求是专门的或动态的,它可以为您做很多事情。

    【讨论】:

      【解决方案2】:

      我不知道什么级别的灵活性足够好,但是如果您有一个包含您感兴趣的所有字段的实体超类,那么您可以使用通用存储库

      public interface MyGenericRepository<E extends MEntity> extends JpaRepository<E,Long> {
      
        @Query("select e from #{#entityName} e where u.someField = ?1 or e.someOtherField = ?1")
        List<E> findBySomeFieldOrSomeOtherField(String query);
      }
      

      docs

      【讨论】:

      • 这就是我在#2 所拥有的,但现在我们没有使用任何查询生成器,因此查询是硬编码的。
      猜你喜欢
      • 2018-08-30
      • 1970-01-01
      • 2021-10-13
      • 2020-02-08
      • 2020-04-15
      • 1970-01-01
      • 2021-09-15
      • 2022-01-24
      • 1970-01-01
      相关资源
      最近更新 更多