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

And*_*ose 19 java hibernate jpa criteria-api spring-data-jpa

我有以下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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我将此规范传递给.findAll()my 的方法,PagingAndSoringRepository以检索Page<Contact>包含Contact符合搜索条件的所有实体的方法.

这是Repository.

@Repository
public interface PagingAndSortingContactRepository extends PagingAndSortingRepository<Contact, Long>, JpaSpecificationExecutor<Contact> {    
}
Run Code Online (Sandbox Code Playgroud)

以下是我如何调用该.findAll()方法.

final Page<Contact> contacts = pagingAndSortingContactRepository.findAll(ContactSpecification.findByApp(appIds), pageable);
Run Code Online (Sandbox Code Playgroud)

这将工作并返回与传入的id对应的Contact任何实体绑定的所有实体ManagedApplication.但是,由于我要调用实体.join()加入实体,如果app id列表中有多个实体,那么查询将返回重复的实体.ContactManagedApplicationContactManagedApplicationContact

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

我知道CriteriaQuery有一个.distinct()方法可以传递一个布尔值,但我没有CriteriaQuerytoPredicate()我的方法中使用该实例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;
}
Run Code Online (Sandbox Code Playgroud)

ManagedApplication_.java

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

Ish*_*Ish 47

使用方法中的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);
    ...
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你这个解决方案,它很棒!另外,为了澄清,你必须将`query.distinct(true)`添加到需要这个不同语句的每个谓词中.仅仅将此语句添加到任何谓词并使其适用于整个查询是不够的. (3认同)

Pan*_*los 7

可以添加一个新的静态方法

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

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

Specification.where(
    YourStaticClassWhereYouCreatedTheUpperMethod.distinct().and(..))
Run Code Online (Sandbox Code Playgroud)