Получение уникальных записей из базы данных wiew для разбивки на страницы с данными Spring - PullRequest
0 голосов
/ 29 мая 2020

У меня есть представление базы данных (MariaDB), которое содержит данные, основанные на нескольких отношениях таблиц. Основная проблема заключается в том, что представление может содержать несколько записей для одного и того же внешнего объекта, в зависимости от того, сколько «проектов» им было назначено. Например,

Person 1 -> Project A -> Role
       -> Project B -> Role
       -> Project C -> Role
Person 2 -> Project A -> Role

Итак, если Person назначен нескольким проектам, то представление будет выглядеть так:

person_id | person_name | project    | role
---------------------------------------------
1         | Person 1    | Project A  | Role
1         | Person 1    | Project B  | Role
1         | Person 1    | Project C  | Role
2         | Person 2    | Project A  | Role

Когда я показываю список во внешнем интерфейсе, я нужно отображать только одну запись для каждого человека, независимо от того, сколько записей. Проблема, с которой я столкнулся в данный момент, - это получение правильной статистики для разбивки на страницы во внешнем интерфейсе моего приложения, поскольку числа неверны, в зависимости от того, выполняется ли какая-либо фильтрация. Я делаю это, используя данные Spring следующим образом:

private Page<ViewPersons> filterPersons(List<Filter> filters, int page, int size,
                                                     String sortBy, Sort.Direction direction) {

            Page<ViewPersons> distinctPage = this.ViewPersonssRepository.findAll((Specification<ViewPersons>) (root, query, criteriaBuilder) -> {
                List<Predicate> predicates = new ArrayList<>();
                filters.forEach(filter -> predicates.add(filter.toCriteria(root, criteriaBuilder)));
                query.distinct(true);
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }, PageRequest.of(page, size, Sort.by(direction, sortBy)));


            Page<ViewPersons> resultPage = this.ViewPersonssRepository.findAll((Specification<ViewPersons>) (root, query, criteriaBuilder) -> {
                List<Predicate> predicates = new ArrayList<>();
                filters.forEach(filter -> predicates.add(filter.toCriteria(root, criteriaBuilder)));
                query.groupBy(root.get("id"));
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }, PageRequest.of(page, size, Sort.by(direction, sortBy)));

            return new Page<ViewPersons>() {
                @Override
                public int getTotalPages() {
                    return distinctPage.getTotalPages();
                }

                @Override
                public long getTotalElements() {
                    return distinctPage.getTotalElements();
                }

                @Override
                public <U> Page<U> map(Function<? super ViewPersons, ? extends U> function) {
                    return resultPage.map(function);
                }

                @Override
                public int getNumber() {
                    return resultPage.getNumber();
                }

                @Override
                public int getSize() {
                    return size;
                }

                @Override
                public int getNumberOfElements() {
                    return resultPage.getNumberOfElements();
                }

                @Override
                public List<ViewPersons> getContent() {
                    return resultPage.getContent();
                }

                @Override
                public boolean hasContent() {
                    return resultPage.hasContent();
                }

                @Override
                public Sort getSort() {
                    return resultPage.getSort();
                }

                @Override
                public boolean isFirst() {
                    return resultPage.isFirst();
                }

                @Override
                public boolean isLast() {
                    return resultPage.isLast();
                }

                @Override
                public boolean hasNext() {
                    return resultPage.hasNext();
                }

                @Override
                public boolean hasPrevious() {
                    return resultPage.hasPrevious();
                }

                @Override
                public Pageable nextPageable() {
                    return resultPage.nextPageable();
                }

                @Override
                public Pageable previousPageable() {
                    return resultPage.previousPageable();
                }

                @Override
                public Iterator<ViewPersons> iterator() {
                    return resultPage.iterator();
                }
            };

Проблема с приведенным выше кодом заключается в том, что, хотя он отлично работает, если я не добавляю никаких фильтров к поиску, когда я ищу человека который имеет, скажем, 6 записей, тогда количество возвращаемых элементов фактически равно 6, хотя возвращенный контент имеет только 1 запись. В остальном все правильно. Если я добавлю query.groupBy(root.get("id")) в первый запрос, все остальное будет неверным: возвращается только одна страница, элементы равны размеру элементов на странице.

У меня нет опыта работы с spring- data, и я уверен, что делаю это неправильно. Спрашивается, а что?

Спасибо

...