Отличные результаты от спецификации Spring Data JPA, использующей join

у меня есть следующие Specification что я использую для запроса любого Contact сущности, которые привязаны к определенным ManagedApplication объекты. Я прохожу в Collection<Long>, который содержит идентификаторы ManagedApplication сущности, которые я ищу.

public static Specification<Contact> findByApp(final Collection<Long> appIds) {
    return new Specification<Contact>() {
        @Override
        public Predicate toPredicate(Root<Contact> root, CriteriaQuery<?> query, CriteriaBuilder cb) {            
            final Predicate appPredicate = root.join(Contact_.managedApplications)
                .get(ManagedApplication_.managedApplicationId).in(appIds);
        }
    }
}

я передаю эту спецификацию .findAll() метод PagingAndSoringRepository для получения Page<Contact>, который будет содержать все Contact сущности, удовлетворяющие критериям поиска.

здесь Repository.

@Repository
public interface PagingAndSortingContactRepository extends PagingAndSortingRepository<Contact, Long>, JpaSpecificationExecutor<Contact> {    
}

и здесь вот как я называю .findAll() метод.

final Page<Contact> contacts = pagingAndSortingContactRepository.findAll(ContactSpecification.findByApp(appIds), pageable);

это работает и возвращает все Contact сущности, которые привязаны к любому из ManagedApplication сущности, соответствующие переданным идентификаторам. Однако, поскольку я звоню .join() присоединиться к Contact сущности ManagedApplication лица, если один Contact несколько ManagedApplication сущности в списке идентификаторов приложений, затем запрос вернет дубликат Contact объекты.

так что я хочу знать, как я могу получить только отдельные Contact сущности, возвращенные из моего запроса с помощью этого Specification?

я знаю, что CriteriaQuery есть .distinct() метод, которому вы можете передать логическое значение, но я не использую CriteriaQuery экземпляр toPredicate() метод Specification.

вот соответствующие разделы моих метамоделей.

Contact_.java:

@StaticMetamodel(Contact.class)
public class Contact_ {
    public static volatile SingularAttribute<Contact, String> firstNm;
    public static volatile SingularAttribute<Contact, String> lastNm;
    public static volatile SingularAttribute<Contact, String> emailAddress;
    public static volatile SetAttribute<Contact, ManagedApplication> managedApplications;
    public static volatile SetAttribute<Contact, ContactToStructure> contactToStructures;
}

Managedapplication.java

@StaticMetamodel(ManagedApplication.class)
public class ManagedApplication_ {
    public static volatile SingularAttribute<ManagedApplication, Integer> managedApplicationId;
}

1 ответов


использовать в своем toPredicate метод для вызова метода distinct.

пример:

public Predicate toPredicate(Root<Contact> root, CriteriaQuery<?> query, CriteriaBuilder cb) {            
    final Predicate appPredicate = root.join(Contact_.managedApplications)
        .get(ManagedApplication_.managedApplicationId).in(appIds);
    query.distinct(true);
    ...