У меня есть представление базы данных (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, и я уверен, что делаю это неправильно. Спрашивается, а что?
Спасибо