JPA 2.1 Predicate, Критерии для дочерней сущности - PullRequest
0 голосов
/ 08 декабря 2018

Я использую JPA 2.1, Spring Data и использую CriteriaBuilder, Predicates, чтобы выполнить запрос к моей сущности JPA.У меня есть родительский объект InvoiceSummary с отношением @OneToMany с дочерним объектом под названием ShipmentStop.Я хочу установить критерии для дочерней сущности ShipmentStop, но не знаю, как это сделать.Я также хочу возможность устанавливать критерии для родительской и дочерней таблиц одновременно.Есть ли способ сделать это с помощью предикатов?Например, я хочу выполнить поиск по полямpartDate, 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()));
    }
}

Вот мой родительский открытый класс Entity Invoice {

@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;

1 Ответ

0 голосов
/ 08 декабря 2018

Вы можете попробовать подзапрос, что-то вроде:

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);
...