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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33025213/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 21:05:58  来源:igfitidea点击:

Distinct results from Spring Data JPA Specification that uses join

javahibernatejpaspring-data-jpacriteria-api

提问by Andrew Mairose

I have the following Specificationthat I use to query for any Contactentities that are tied to certain ManagedApplicationentities. I pass in a Collection<Long>that contains the ids of the ManagedApplicationentities that I am searching for.

我有以下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);
        }
    }
}

I pass this specification to the .findAll()method of my PagingAndSoringRepositoryto retrieve a Page<Contact>that will contain all Contactentities that meet the search criteria.

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

Here is the Repository.

这是Repository.

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

And here is how I'm calling the .findAll()method.

这是我调用该.findAll()方法的方式。

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

This works and returns all Contactentities that are tied to any of the ManagedApplicationentities that correspond to the ids passed in. However, since I am calling .join()to join the Contactentity with the ManagedApplicationentity, if one Contacthas multiple ManagedApplicationentities in the list of app ids, then the query will return duplicate Contactentities.

这有效并返回与传入的 id 对应的Contact任何实体相关联的所有实体ManagedApplication。 但是,由于我正在调用.join()Contact实体与ManagedApplication实体连接,如果应用程序 id 列表中Contact有多个ManagedApplication实体,则查询将返回重复的Contact实体。

So what I need to know is, how can I get only distinct Contactentities returned from my query using this Specification?

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

I know that CriteriaQueryhas a .distinct()method that you can pass a boolean value to, but I am not using the CriteriaQueryinstance in the toPredicate()method of my Specification.

我知道CriteriaQuery有一个.distinct()方法可以将布尔值传递给它,但我没有CriteriaQuerytoPredicate()我的Specification.

Here are the relevant sections of my metamodels.

这是我的元模型的相关部分。

Contact_.java:

联系人_.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

ManagedApplication_.java

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

回答by Ish

Use the queryparameter in your toPredicatemethod to invoke the distinct method.

使用方法中的query参数toPredicate来调用不同的方法。

Sample below:

示例如下:

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