如何有条件地添加JPA规范进行查询?

How to add JPA specifications conditionally to query?

我正在尝试在 JPA 中的 sqlfiddle 上编写此处概述的以下查询。我首先尝试将 @query 注释与 native = true 一起使用并且确实有效,但我的问题是我希望查询更加动态,因为可能是我不想添加的情况按名称或帐户过滤的子句。

我的实体看起来像这样:

@Entity
@Table(name = "INSTRUCTION")
public class Instruction {

    @Id
    @Column(name = "ID", nullable = false, unique = true)
    public Long id;

    @Column(name = "ACCOUNT", nullable = false)
    public String account;

    @Column(name = "NAME", nullable = false)
    public String name;

    @OneToMany(cascade = CascadeType.All, fetch = FetchType.EAGER)
    @JoinColumn(name = "INSTRUCTION_ID", referenceColumnName = "ID")
    @OrderBy("lastUpdated")
    private List<Audit> auditItems = new ArrayList<>();

    //Getters & Setters
}

.

@Entity
@Table(name = "AUDIT")
public class Audit {

    @Id
    @Column(name = "ID", nullable = false, unique = true)
    public Long id;

    @Column(name = "INSTRUCTION_STATUS", nullable = false)
    public InstructionStatus status;

    @Column(name = "LAST_UPDATED", nullable = false)
    public LocalDateTime lastUpdated;

    @Column(name = "LAST_UPDATED_BY", nullable = false)
    public String lastUpdatedBy;

    //Getters & Setters
}

  

我研究过使用规范来执行此操作,并且我设法将查询分解为不同的规范,如下所示:

    private Specification<Instruction> hasAccount(String account) {
        return (root, query, criteriaBuilder) -> criteriaBuilder.in(root.get("account")).value(account);
    }

    private Specification<Instruction> havingStatus(List<String> status) {
        return (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            final Subquery<Audit> auditSubquery = query.subquery(Audit.class);
            final Root<Audit> audit = auditSubquery.from(Audit.class);

            //select instruction id from audit where status is not in {status}
            auditSubquery.select(audit.get("instruction").get("id"));
            auditSubquery.where(criteriaBuilder.trim(audit.get("status")).in(status).not());

            //Select instruction from table where
            predicates.add(root.get("id").in(auditSubquery).not());

            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
    }

    // Other specifications....

像这样调用时它们工作正常:

 final List<Instruction> instructions = this.instructionRepository.findAll(
                where(havingStatus(statuses)
                        .and(hasAccount(account))));

但我的目标是拥有它,例如我可以检查 if account == null 然后不包括 hasAccount 规范,对于其他可能为空的字段依此类推。我有办法做到这一点吗?

这应该可以解决问题。

Specification spec = where(null);
if (statuses != null) {
    spec = spec.and(havingStatus(statuses))
}
if (account != null) {
    spec = spec.and(hasAccount(account))
}

final List<Instruction> instructions = this.instructionRepository.findAll(spec);