我正在使用JPA 2.1,Spring Data,并且正在使用CriteriaBuilder,Predicates对我的JPA实体进行查询。我有一个父实体InvoiceSummary与一个名为ShipmentStop的子实体具有@OneToMany关系。我想在子实体ShipmentStop上设置标准,但不确定如何执行此操作。我还希望能够同时在父表和子表上设置条件。有没有办法使用谓词做到这一点?例如,我要按子实体的离开日期,isFirstPick,isLastDrop字段进行搜索。除子实体搜索条件外,我还可能要搜索父实体DueDate。以下是我实体的代码,以及如何生成查询的代码。
这是我的条件构建器
public Specification<T> isBetween(List<RangeFilter> filters) {
return new Specification<T>() {
@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
List<Predicate> predicates = new ArrayList<>();
for (RangeFilter filter: filters) {
if (!filter.getStartValue().isEmpty()) {
mapFilterCriteria(root, criteriaBuilder, predicates, filter);
}
}
return criteriaBuilder.and(predicates.toArray(new Predicate[]{}));
}
};
}
private void mapFilterCriteria(Root<T> root, CriteriaBuilder criteriaBuilder, List<Predicate> predicates, RangeFilter filter) {
if(root.get(filter.getName()).getJavaType().getName().equals("java.time.LocalDateTime")) {
predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get(filter.getName()), convertStringToLocalDate(filter.getStartValue())));
predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get(filter.getName()), convertStringToLocalDate(filter.getEndValue())));
}
else {
predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get(filter.getName()), filter.getStartValue()));
predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get(filter.getName()), filter.getEndValue()));
}
}
这是我的父实体 公共类发票{
@Id
@Column(name = "shipment_id")
private int shipmentId;
@Column(name = "customer_id")
private int customerId;
@Column(name = "invoice_date")
@JsonFormat(pattern = "MM/dd/yyyy HH:mm")
private LocalDateTime invoiceDate;
@Column(name = "due_date")
private String dueDate;
@OneToMany(mappedBy = "invoice",
cascade = CascadeType.ALL,
orphanRemoval = true)
private List<ShipmentStop> shipmentStops;
这是我的孩子实体
@Entity
@Table(name = "shipment_stops")
public class ShipmentStop {
@Id
@Column(name = "shipment_stop_id")
private int shipmentStopId;
@Column(name = "shipment_id")
private int shipmentId;
@ManyToOne
@JoinColumn(name = "stop_type_id", referencedColumnName = "stop_type_id")
private ShipmentStopType shipmentStopType;
@Column(name = "is_firstpick")
private boolean isFirstPick;
@Column(name = "is_lastdrop")
private boolean isLastDrop;
@Column(name = "depart_date")
@JsonFormat(pattern = "MM/dd/yyyy HH:mm:ss")
private LocalDateTime departDate;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "shipment_id", insertable = false, updatable = false)
private Invoice invoice;
答案 0 :(得分:0)
您可以尝试子查询,例如:
Subquery<?> subQuery = query.subquery(ShipmentStop.class);
Root<?> rootChild = subQuery.from(ShipmentStop.class);
subQuery
.select(rootChild.join("shipmentId"))
.where(criteriaBuilder.and(predicate1, predicate2)); // your predicates on children
root.get("shipmentId").in(subQuery);