Добавить предложение WHERE IN в спецификацию JPA - PullRequest
0 голосов
/ 09 июля 2019

Я пытаюсь реализовать функцию поиска, ограниченную предложением IN:

Я хочу реализовать реализацию поиска с ограничением фильтра:

    @GetMapping("find")
    public Page<MerchantUserDTO> getAllBySpecification(
            @And({
                @Spec(path = "name", spec = LikeIgnoreCase.class),
                @Spec(path = "login", spec = LikeIgnoreCase.class),
                @Spec(path = "email", spec = LikeIgnoreCase.class),
            }) Specification<Users> specification,
            @SortDefault(sort = "login", direction = Sort.Direction.DESC) Pageable pageable
    ) {        
        return merchantUserService.getAllBySpecification(specification, pageable)
                .map(g -> MerchantUserDTO.builder()                   
                        .id(g.getId())
                        .login(g.getLogin())                        
                        .build()
                );
    }

    @Override
    public Page<Users> getAllBySpecification(Specification<Users> specification, Pageable pageable) {
        return dao.findAllByTypeIn(specification, pageable, "MerchantUser");
    }

Repository:

@Repository
public interface MerchantUserRepository extends JpaRepository<Users, Integer>, JpaSpecificationExecutor<Users> {

    Page<Users> findAllByTypeIn(Pageable page, String... types);

    Page<Users> findAllByTypeIn(Specification<Users> specification, Pageable pageable, String... types);
}

Как правильно расширить спецификацию с помощью предложения IN?

specification.and(path.in(types)) путь является атрибутом, но как правильно его реализовать?

1 Ответ

1 голос
/ 13 июля 2019

Обычно это может быть достигнуто следующим образом:

1) Создать реализацию спецификации

public class MerchantUserSpecification implements Specification<Users> {

    private final List<String> types;

    public MerchantUserSpecification(List<String> types) {
        this.types = types;
    }

    @Override
    public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        if (types != null && !types.isEmpty()) {
            return root.get(Users_.type).in(types);
        } else {
            // always-true predicate, means that no filtering would be applied
            return cb.and(); 
        }
    }

2) Использовать метод Page findAll (спецификация спецификации @Nullable, Pageable pageable); унаследовано от JpaSpecificationExecutor интерфейса вместо использования вашего пользовательского findAllByTypeIn(Specification<Users> specification....)

@Override
public Page<Users> getAllBySpecification(Specification<Users> specification, Pageable pageable) {
    // combine original specification (passed from outside) and filter-by-types specification
    Specification<Users> finalSpec = specification
           .and(new MerchantUserSpecification(Arrays.asList("MerchantUser")))
    return dao.findAll(finalSpec, pageable)
}

PS

С Java 8+ и для простых случаев (таких как ваш) код может быть уменьшен еще больше.Вместо реализации Specification<T> в отдельном классе вы можете просто создать метод

private Specification<Users> typeIn(List<String> types) {
    return (root, query, cb) -> {
        if (types != null && !types.isEmpty()) {
           return root.get(Users_.type).in(types);
        } else {
           // always-true predicate, means that no filtering would be applied
           return cb.and(); 
        }
    }
}

@Override
public Page<Users> getAllBySpecification(Specification<Users> specification, Pageable pageable) {
    // combine original specification (passed from outside) and filter-by-types specification
    Specification<Users> finalSpec = specification
            .and(typeIn(Arrays.asList("MerchantUser")))
    return dao.findAll(finalSpec, pageable)
}

ОБНОВЛЕНИЕ: Кратчайший путь

@Override
public Page<Users> getAllBySpecification(Specification<Users> specification, Pageable pageable) {
    // combine original specification (passed from outside) and filter-by-types specification
    Specification<Users> finalSpec = specification
            .and((root, query, cb) -> root.get(Users_.type).in(Arrays.asList("MerchantUser"))
    return dao.findAll(finalSpec, pageable)
}
...