Spring Данные JPA Select Distinct
У меня есть ситуация, когда мне нужно построить select distinct a.address from Person a
(где адрес - это объект Address внутри Person).
Я использую Specification для динамического создания предложения where и с помощью функции findAll(Specification<T>)
, чтобы получить результат. Проблема в том, что я не могу использовать спецификацию для построения предложения select и, следовательно, не могу использовать функцию findAll(Spcification)
.
Каким будет лучший способ сделать что-то подобное?
Ответы
Ответ 1
Я столкнулся с одной и той же проблемой, поэтому, если это поможет кому-то, это то, что я сделал:
Спецификация переводится в предложение where, а функция findAll(Specification<T>)
создает свое собственное предложение select. Поэтому мы никак не можем это исправить, используя функцию findAll(Specification<T>)
.
У меня уже был пользовательский репозиторий, который расширяет SimpleJpaRepository
, поэтому я добавил новый метод:
@Override
@Transactional(readOnly = true)
public List<Object> findDistinctValues(Specifications<T> spec, String columnName) {
return getQuery(spec, columnName).getResultList();
}
protected TypedQuery<Object> getQuery(Specification<T> spec, final String distinctColumnName) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Object> query = builder.createQuery(Object.class);
Root<T> root = applySpecificationToCriteria(spec, query);
if (null != distinctColumnName) {
query.distinct(true);
query.multiselect(root.get(distinctColumnName));
}
// We order by the distinct column, Asc
query.orderBy(builder.asc(root.get(distinctColumnName)));
return em.createQuery(query);
}
applySpecificationToCriteria
находится в классе SimpleJpaRepository
.
Теперь вы можете использовать метод findDistinctValues
.
Ответ 2
Как главный вопрос в google, я отправлю ответ здесь.
В спецификации у вас есть доступ к запросу, поэтому вы можете сделать
query.distinct(true);
Полный пример, который приводит к выходу такого SQL:
2015-04-27 12:03:39 EEST [7766-759] postgres @sales LOG: выполнить: SELECT DISTINCT t1.ID, t1.NAME, t1.WEBNAME, t1.WEBORDER, t1.PVGROUPPARENT_ID, t1.SITE_ID FROM PRODUCTVARIANT t0, PVGROUP t1 WHERE ((t0.PRODUCTTYPE_ID = $1) И (t0.PVGROUP_ID = t1.ID)) 2015-04-27 12:03:39 EEST [7766-760] postgres @sales ДЕТАЛИ: параметры: $1 = '4608bdc9-d0f2-4230-82fd-b0f776dc2cfd'
public static Specification<PVGroup> byProductType(final ProductType pt) {
return (final Root<PVGroup> root, final CriteriaQuery<?> query, final CriteriaBuilder builder) -> {
query.distinct(true);
final CollectionJoin<PVGroup, ProductVariant> jPV = root.join(PVGroup_.productVariant);
final Path<ProductType> ptPath = jPV.get(ProductVariant_.productType);
return builder.equal(ptPath, pt);
};
}
}
Ответ 3
Быстрое и грязное решение - это фильтрация результата с помощью Set
:
Set<...> set = new HashSet<...>( findAll( ... ) )
и убедитесь, что equals()
и hashCode()
релевантно реализованы в классе домена: -)
Приветствия,
Ответ 4
Хорошо! Вы можете использовать distinct
в JPQL
, а также для определенного столбца. Здесь уже .
Ссылка Использование DISTINCT в JPA
Ответ 5
Будет ли это работать?
List<Person> findDistinctPeopleByAddress(String lastname, String firstname);
за которым следует повторение списка и использование Person.getAddress()?