Spring boot jpa построитель запросов для совокупных значений? - PullRequest
0 голосов
/ 17 мая 2019

Я хотел бы создать настраиваемый запрос, который выводит агрегированные значения.Я знаю три способа получить и выполнить запрос, но ни один из них не подходит.Запросы, которые я хочу построить, выглядят примерно так:

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")...
    • Pro: мы можем получить доступ к результату из запроса
    • Con: Он не использует построитель запросов: мы должны сами построить строку "select ...".
  2. Использование репозиториев
    • public interface MytableRepository extends CrudRepository<Mytable, Integer> { @Query("Select ...") public List<Object[]> findMinMaxPrice(@Param("myParam") String myParam);
    • Pro: мы можем получить доступ к результату запроса.
    • Con: запрос жестко закодирован
  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, не так ли?

Как использовать построитель запросов с гибким типом результата?

Ответы [ 2 ]

1 голос
/ 18 мая 2019

Возможно, вы захотите заглянуть в 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 являются специализированными или динамическими.

0 голосов
/ 17 мая 2019

Я не знаю, какой уровень гибкости достаточно хорош, но если у вас есть один суперкласс сущностей, который имеет все интересующие вас поля, то вы можете использовать общий репозиторий

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

* документы 1005 *

...