spring – 如何在没有’distinct’的情况下执行此操作:选择Distinct(x)from x Left Join y其中y.attr = true

我陷入了查询,我使用的是Spring Data JPA,JpaRepository和JpaSpecificationExecutor.所以我必须使用CriteriaBuilder的Predicates.

目前我只是这样做:

Specifications<MyEntity> spec = Specifications.where(MySpec.isTrue());
List<MyEntity> myEntities = myRepository.findAll(spec);

MySpec.isTrue()的位置是:

public static Specification<MyEntity> isTrue() {
    return new Specification<MyEntity>() {
        @Override
        public Predicate toPredicate(Root<MyEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            SetJoin<MyEntity, JoinEntity> j = root.join(MyEntity.joinEntities, JoinType.LEFT);  
            return cb.isTrue(j.get(JoinEntity_.attr));
        }
    };
}

所以这当然会导致这个SQL:

SELECT e.* FROM MyEntity e
  LEFT OUTER JOIN JoinEntity j ON j.myEntityId = e.id
  WHERE j.attr = true

但我只对MyEntitys这套独一无二的东西感兴趣.所以在JPQL中我会写:

SELECT DISTINCT(e) FROM MyEntity e
  LEFT JOIN e.joinEntities j
  WHERE j.attr = true

现在我的解决方案是:

List<MyEntity> myEntities = myRepository.findAll(spec);
Set<MyEntity> entitiesSet = new HashSet<MyEntity>(myEntities);

必须有一个更好的方式;)

它如何与CriteriaBuilder(和JpaSpecificationExecutor)一起使用?

解决方案:

第一个想法是一个简单的区别:

public static Specification<MyEntity> isTrue() {
    return new Specification<MyEntity>() {
        @Override
        public Predicate toPredicate(Root<MyEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            SetJoin<MyEntity, JoinEntity> j = root.join(MyEntity.joinEntities, JoinType.LEFT);
            query.distinct(true); // <<-- HERE  
            return cb.isTrue(j.get(JoinEntity_.attr));
        }
    };
}

这有效但有点破坏了那些小规格件的感觉.所以我想出了一个使用子查询的解决方案.这可能需要一些额外的时间,但对我而言,目前并不重要:

public static Specification<MyEntity> isTrue() {
    return new Specification<MyEntity>() {
        @Override
        public Predicate toPredicate(Root<MyEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            Subquery<JoinEntity> subquery = query.subquery(JoinEntity.class);
            Root<JoinEntity> subRoot = subquery.from(JoinEntity.class);
            subquery.select(subRoot);
            subquery.where(cb.isTrue(subRoot.get(JoinEntity_.attr)));
            subquery.groupBy(subRoot.get(JoinEntity_.myEntity));

            return cb.exists(subquery);
        }
    };
}

解决方法:

你在找CriteriaQuery.distinct(true)

上一篇:如何使用多列构建CriteriaQuery谓词IN子句?


下一篇:Mybatis逆向工程的全部使用