简体   繁体   English

Spring Boot JPA查询生成器以获取汇总值?

[英]Spring boot jpa query builder for aggregate values?

I'd like to create customizable query that output aggregate values. 我想创建可输出汇总值的可定制查询。 I know three ways to get and execute a query, but none of them seem to suffice. 我知道三种获取和执行查询的方法,但是似乎都不足够。 The queries I want to build look something like this: 我要构建的查询如下所示:

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

tldr: skip 1 & 2. tldr:跳过1和2。

  1. SQL as String SQL作为字符串
    • private NamedParameterJdbcTemplate template; template.query("select ..." , new MapSqlParameterSource("...", "...") , rs -> {...rs.getString("minprice")...
    • Pro: we can access the result from the query 亲:我们可以从查询中访问结果
    • Con: It is not using a query builder: we have to build the "select..." string ourselves. 缺点:它没有使用查询生成器:我们必须自己构建“ select ...”字符串。
  2. Using repositories 使用储存库
    • public interface MytableRepository extends CrudRepository<Mytable, Integer> { @Query("Select ...") public List<Object[]> findMinMaxPrice(@Param("myParam") String myParam);
    • Pro: We can access the result from the query. 优点:我们可以从查询中访问结果。
    • Con: The query is hardcoded 缺点:查询是硬编码的
  3. Using the query builder 使用查询生成器
    • 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: It is using the query builder 优点:正在使用查询生成器
    • Con: The query is not using the groupBy. 缺点:查询未使用groupBy。 Since our groupBy query is not returning records of class Mytable but aggregate values, I don't see how I can make this work. 由于我们的groupBy查询不是返回Mytable类的Mytable而是聚集值,因此我看不到如何进行这项工作。 I start selecting from Mytable so I think I need to use it as type parameter to Specification , but that immediately implies that the result should also be of type MyTable , doesn't it? 我开始从Mytable选择,所以我认为我需要将其用作Specification类型参数,但这立即意味着结果也应该是MyTable类型,不是吗?

How can I use a query builder with a flexible result type? 如何使用具有灵活结果类型的查询生成器?

You might consider looking in to jOOQ, which would give you as much flexibility as you wish while keeping your queries "in code", so to speak. 您可以考虑使用jOOQ,可以这样给您带来尽可能多的灵活性,同时可以将查询保持在“代码中”状态。

It can generate Java classes from your database schema, which you use to form queries using its DSL. 它可以从您的数据库模式生成Java类,您可以使用它使用其DSL进行查询。 Here's an example: https://github.com/benjamin-bader/droptools/blob/master/droptools-example/src/main/java/com/bendb/example/resources/PostsResource.java#L99 这是一个示例: https : //github.com/benjamin-bader/droptools/blob/master/droptools-example/src/main/java/com/bendb/example/resources/PostsResource.java#L99

Here's the meat of the code I linked above: 这是我上面链接的代码的内容:

    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();

It looks a little funky, but here's what it generates: 它看起来有些时髦,但这是生成的内容:

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

You can see that the Java code closely mirrors the generated SQL, but thanks to jOOQ's generated code, it is still perfectly typesafe. 您可以看到Java代码与生成的SQL非常相似,但是由于jOOQ生成的代码,它仍然是完全类型安全的。 Because it's code, you can dynamically build up queries as you see fit. 因为它是代码,所以您可以根据需要动态构建查询。

It's a heavy dependency to take on, but it can do a lot for you if your SQL needs are specialized or dynamic. 这是一个很严重的依赖关系,但是如果您的SQL需求是专门的或动态的,它可以为您做很多事情。

I don't know what level of flexibility is good enough, but if you have one entity superclass which has all the fields that you're interested in, then you can use generic repository 我不知道什么级别的灵活性足够好,但是如果您有一个实体超类,其中包含您感兴趣的所有字段,那么可以使用通用存储库

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 文档

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM