【问题标题】:Spring JpaRepository findBy...In(Collection) returns union not intersectionSpring JpaRepository findBy...In(Collection) 返回联合而不是交集
【发布时间】:2018-05-11 16:12:17
【问题描述】:
我的 JpaRepository 中有一个查询方法
Page<Course> findDistinctCourseByAttrsInAllIgnoreCase(Set<String> a, Pageable page);
通过实例变量Set<String> attrs 查找Course 对象。给定一个带有“foo”和“bar”的集合a,我想找到Courses,它的attrs同时包含“foo”和“bar”,即@987654327的交集带有“foo”的@s 和带有“bar”的@s。上面的这个方法返回一个联合。
有没有办法通过 JpaRepository 查询来做到这一点,还是我必须自己打多个电话才能找到交叉点?
【问题讨论】:
标签:
mysql
spring
hibernate
spring-data-jpa
spring-repositories
【解决方案1】:
如果您预先知道as 的数量,您可以将多个约束与And 结合使用:
...AttrsInAndAttrsIn...
但即使前提条件成立,那也会非常难看。
因此,下一个最佳选择可能是 Specification 和 factoryMethod,从 Set<String> 或 varargs 构造 Specification。
您的存储库需要扩展 JpaSpecificationExecutor。
你会这样称呼它
Page<Course> findAll(matchesAll(attrs), pageable)
工厂方法看起来像这样:
Specification<Course> matchesAll(Set<String> attrs) {
return (Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) -> {
// construct Predicate by combining calls to builder.isMember
// https://docs.oracle.com/javaee/6/api/javax/persistence/criteria/CriteriaBuilder.html#isMember(E,%20javax.persistence.criteria.Expression)
}
}
【解决方案2】:
应该是这样的:
@Query("SELECT c FROM Course c JOIN Attribute a WHERE LOWER(a.name) IN (:attributes) GROUP BY c HAVING COUNT(c) = :size")
public Page<Course> findByAllAttributes(@Param("attributes") Set<String> attributes, @Param("size") Integer size, Pageable page);
你这样称呼它:
Page<Course> page = findByAllAttributes(set.stream()
.map(String::toLowerCase)
.collect(Collectors.toSet(),
set.size(), page);