【问题标题】:Add WHERE IN clause to JPA Specification将 WHERE IN 子句添加到 JPA 规范
【发布时间】:2019-11-19 10:31:09
【问题描述】:

我正在尝试实现受 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
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)) path 是一个属性但是如何正确实现呢?

【问题讨论】:

  • 您需要帮助的具体问题是什么?
  • @JensSchauder 上述规范工作正常,但我想限制所有带有 IN 子句的 SELECT 子句(WHERE type IN ('MerchantUser'))。如何将此条款添加到规范中?你能给我一些代码示例怎么做吗?
  • @JensSchauder 我也试过了,但它不起作用stackoverflow.com/questions/56942688/…
  • 向我们展示您的尝试以及失败的原因。
  • @JensSchauder 我已经尝试了上面的代码。这是错误堆栈:pastebin.com/WJrJRC01

标签: spring-boot jpa spring-data-jpa jpa-2.0 jpa-2.1


【解决方案1】:

一般可以这样实现:

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) 使用继承自JpaSpecificationExecutor 接口的Page findAll(@Nullable Specification spec, Pageable pageable); 方法,而不是使用您自定义的findAllByTypeIn(Specification&lt;Users&gt; 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)
}

附言

使用 Java 8+ 以及对于简单情况(如您的情况),代码可能会进一步减少。不用在单独的类中实现Specification&lt;T&gt;,您只需创建一个方法

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)
}

【讨论】:

  • 谢谢,以防万一您可以通过其他方式向我展示更简单的代码?
  • @PeterPenzov 我不知道更短的方法
  • @PeterPenzov Null & emptiness check of types collection 可能会被删除以缩短代码,如果你确定它总是非空的
  • 一个问题。你从哪里得到Users_
  • @PeterPenzov 它是Users 实体类的元模型类。它由 Hibernate 处理器生成。详情看这里docs.jboss.org/hibernate/jpamodelgen/1.0/reference/en-US/…
猜你喜欢
  • 1970-01-01
  • 2011-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-07
相关资源
最近更新 更多