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

我有以下内容,用于查询与某些实体绑定的任何实体。我传入一个,其中包含我正在搜索的实体的 ID。SpecificationContactManagedApplicationCollection<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);
        }
    }
}

我将此规范传递给 my 的方法,以检索将包含满足搜索条件的所有实体的 a。.findAll()PagingAndSoringRepositoryPage<Contact>Contact

这是 .Repository

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

这就是我如何调用该方法。.findAll()

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

这将起作用并返回与传入的 ID 对应的任何实体绑定的所有实体。但是,由于我调用将实体与实体联接,因此如果一个实体在应用程序 ID 列表中有多个实体,则查询将返回重复的实体。ContactManagedApplication.join()ContactManagedApplicationContactManagedApplicationContact

所以我需要知道的是,如何使用这个来只从我的查询返回不同的实体?ContactSpecification

我知道有一个方法,你可以将一个布尔值传递给,但我没有在我的方法中使用实例。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;
}

ManagedApplication_.java

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

答案 1

使用方法中的参数调用不同的方法。querytoPredicate

示例如下:

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);
    ...

答案 2

可以添加新的静态方法

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

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

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

推荐