Hibernate - группировать по столбцу, собирать в список и ограничивать - PullRequest
0 голосов
/ 06 мая 2020

В моем приложении у меня есть таблица customer_facts, представленная объектом гибернации:

@Entity
data class PersistedCustomerFacts(
    @Id
    val id: Long,
    val customerId: String
    val factValue: String
)

Она хранит все факты клиентов. У каждого покупателя может быть несколько фактов. Я хочу запросить таблицу и получить результат, состоящий из списка каждого идентификатора клиента с его фактами. Но я также хочу, чтобы он был доступен для страницы по идентификатору клиента, поэтому, например, я могу получить только первых двух клиентов. Хочу показать пример. Допустим, \ я хочу получить первые два результата, упорядоченные по идентификатору клиента

Данные в базе данных:

id, customerId, factValue
1, 'customerA', 'likes cats'
2, 'customerA', 'likes dogs'
3, 'customerA', 'doesnt likes rats'
4, 'customerB', 'likes cats'
5, 'customerB', 'likes rats'
6, 'customerB', 'likes bikes'
7, 'customerB', 'doesnt likes cats'
8, 'customerC', 'doesnt likes bikes'

окончательный результат будет

[
    {
        "customerId": "customerA",
        "facts": ["likes cats", "likes dogs", "doesnt likes rats"]
    },
    {
        "customerId": "customerB",
        "facts": ["likes cats", "likes rats", "likes bats"]
    },
]

I Надеюсь, теперь понятно, что у меня возникла проблема, особенно с тем, как сделать так, чтобы результат был доступен для страницы с помощью поля customerId. Я пробовал что-то вроде этого:

        val criteriaBuilder = entityManager.criteriaBuilder
        val criteriaQuery = criteriaBuilder.createQuery(PersistedCustomerFacts::class.java)
        val customerFacts = criteriaQuery.from(PersistedCustomerFacts::class.java)
        criteriaQuery
            .select(customerFacts)
            .orderBy(criteriaBuilder.asc(customerFacts.get("customerId")));
        val typedQuery = entityManager.createQuery(criteriaQuery)
        typedQuery.firstResult = 0
        typedQuery.maxResults = 2
        return typedQuery.resultList

Однако это плохо, потому что я ограничиваю строки, поэтому я не могу получить все факты некоторого customerId. Как решить такую ​​проблему? Может, мне сделать два запроса?

1 Ответ

0 голосов
/ 07 мая 2020

Это идеальный вариант использования API богатой разбивки на страницы , предоставляемого Blaze-Persistence, который представляет собой библиотеку, работающую поверх JPA!

Есть несколько способов сделать это , но для простоты я предполагаю, что у вас есть обратная ассоциация @OneToMany @JoinColumn(name = "customerId") Set<PersistedCustomerFacts> facts, отображенная в вашей Customer сущности.

С помощью API разбивки на страницы вы можете написать запрос, подобный следующему

CriteriaBuilder<Customer> cb = criteriaBuilderFactory.create(entityManager, Customer.class);
cb.fetch("facts");
PaginatedCriteriaBuilder<Customer> pcb = cb.page(0, 2);
return pcb.getResultList();

Если у вас нет этой обратной связи, вы можете использовать функцию агрегирования строк

CriteriaBuilder<Tuple> cb = criteriaBuilderFactory.create(entityManager, Tuple.class);
cb.from(PersistedCustomerFacts.class, "fact");
cb.select("fact.customerId");
cb.select("GROUP_CONCAT(fact.factValue, 'SEPARATOR', ';')");
cb.groupBy("fact.customerId");
PaginatedCriteriaBuilder<Tuple> pcb = cb.page(0, 2);
return pcb.getResultList();

, а затем разделить строку на коллекцию.

Если у вас есть logi c, записанные с API критериев JPA, который вы хотите использовать повторно, вы можете использовать модуль jpa-критериев, который является реализацией API критериев JPA, который генерирует Blaze-Persistence CriteriaBuilder.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...