使用join的Spring Data JPA规范的不同结果

时间:2015-10-08 20:18:57

标签: java hibernate jpa spring-data-jpa criteria-api

我使用以下Specification来查询与某些Contact实体绑定的任何ManagedApplication实体。我传入Collection<Long>,其中包含我要搜索的ManagedApplication个实体的ID。

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()的{​​{1}}方法,以检索包含符合搜索条件的所有PagingAndSoringRepository个实体的Page<Contact>

这是Contact

Repository

以下是我如何调用@Repository public interface PagingAndSortingContactRepository extends PagingAndSortingRepository<Contact, Long>, JpaSpecificationExecutor<Contact> { } 方法。

.findAll()

这适用于并返回与传入的ID对应的任何final Page<Contact> contacts = pagingAndSortingContactRepository.findAll(ContactSpecification.findByApp(appIds), pageable); 实体绑定的所有Contact个实体。但是,因为我正在调用ManagedApplication加入{ {1}}具有.join()实体的实体,如果一个Contact在应用ID列表中有多个ManagedApplication个实体,则该查询将返回重复的Contact个实体。< / p>

所以我需要知道的是,如何才能使用此ManagedApplication从查询中返回不同的Contact个实体?

我知道Contact有一个Specification方法可以传递一个布尔值,但是我没有使用我CriteriaQuery方法中的.distinct()实例CriteriaQuery

以下是我的元模型的相关部分。

Contact_.java:

toPredicate()

ManagedApplication_.java

Specification

2 个答案:

答案 0 :(得分:42)

使用query方法中的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);
    ...

答案 1 :(得分:4)

可以添加新的静态方法

public static Specification<Object> distinct() {
    return (root, query, cb) -> {
        query.distinct(true);
        return null;
    };
}

稍后您可以在创建规范时添加

Specification.where(
    YourStaticClassWhereYouCreatedTheUpperMethod.distinct().and(..))