【问题标题】:Distinct results from Spring Data JPA Specification that uses join使用连接的 Spring Data JPA 规范的不同结果
【发布时间】:2016-01-06 15:09:54
【问题描述】:

我有以下Specification 用于查询与某些ManagedApplication 实体相关联的任何Contact 实体。我传入一个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);
        }
    }
}

我将此规范传递给我的PagingAndSoringRepository.findAll() 方法以检索一个Page&lt;Contact&gt;,它将包含所有满足搜索条件的Contact 实体。

这里是Repository

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

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

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

这有效并返回与传入的 id 对应的任何 ManagedApplication 实体相关联的所有 Contact 实体。但是,由于我调用 .join() 以将 Contact 实体与 @ 987654339@实体,如果一个Contact在app id列表中有多个ManagedApplication实体,那么查询将返回重复的Contact实体。

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

我知道CriteriaQuery 有一个.distinct() 方法,您可以将布尔值传递给它,但我没有在toPredicate()toPredicate() 方法中使用CriteriaQuery 实例@。

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

联系方式_.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;
}

【问题讨论】:

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


    【解决方案1】:

    toPredicate 方法中使用 query 参数来调用 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);
        ...
    

    【讨论】:

    • 感谢您提供此解决方案,效果很好!此外,为了澄清,您必须将query.distinct(true) 添加到需要此不同语句的每个谓词中。仅将此语句添加到任何谓词并使其适用于整个查询是不够的..
    • 这是如何工作的?我的意思是,如果您使用简单的 MySQL 语法来连接一些形成多对多关系的表,以便您可以选择左表中在右表的列中具有特定值的行,尽管您使用 SELECT DISTINCT如果左表中的一行与右表中的多行相关,您仍然会得到重复的结果。
    • 开发人员似乎在Specification 中操作query 参数是discouragedunsupported。但我没有更好的解决方案。
    【解决方案2】:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2017-05-12
      • 2020-10-10
      • 2018-06-15
      • 2019-05-25
      • 2016-07-22
      • 2015-06-03
      • 2021-01-06
      • 1970-01-01
      • 2014-12-29
      相关资源
      最近更新 更多