Spring JpaRepository findByIn (Collection) возвращает объединение, а не пересечение

У меня есть метод запроса в моем JpaRepository

    Page<Course> findDistinctCourseByAttrsInAllIgnoreCase(Set<String> a, Pageable page);

чтобы найти Course объектов по их переменной экземпляра Set<String> attrs. Учитывая набор a с "foo" и "bar", я хочу найти Courses, чьи attrs содержат ОБА "foo" и "bar", т.е. пересечение Courses с "foo" и с " бар". Этот метод выше возвращает объединение.

Есть ли способ сделать это с помощью запросов JpaRepository или мне нужно сделать несколько вызовов и найти пересечение самостоятельно?


person Community    schedule 28.11.2017    source источник


Ответы (2)


В маловероятном случае, когда вы заранее знаете количество a, вы можете объединить несколько ограничений с And:

...AttrsInAndAttrsIn...

Но даже если предварительное условие выполнено, это было бы очень некрасиво.

Таким образом, следующим лучшим вариантом, вероятно, является Спецификация и factoryMethod, создающий Спецификацию из Set<String> или из varargs.

Ваш репозиторий должен расширить 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)

    }
}
person Jens Schauder    schedule 28.11.2017

Что-то вроде этого должно получиться:

@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);
person Bartosz Szymański    schedule 28.11.2017