Критерии JPA - между использованием подзапроса - PullRequest
0 голосов
/ 05 декабря 2018

"Числа в начале запросов и критериев были введены для облегчения объяснения. (1 -...) (2 -...) (3 -...)"

Мне нужно сделать это в критериях JPA:

SELECT DISTINCT service.*
  FROM service AS service 
INNER JOIN service_item AS serviceItem ON serviceItem.fk_service = service.id
INNER JOIN follow_up AS followUp ON followUp.fk_service = service.id
WHERE service.fk_branch = 241 AND service.fk_employee = 403
  AND service.tenant_id = 246 AND customer.status = 'PROSPECT'
  AND service.see_in BETWEEN '2010-01-01' AND '2018-12-31'
  1-AND (SELECT DATEDIFF(MIN(serviceItem.arrival_date), MAX(serviceItem.departure_date))) = 6 
  2-AND (SELECT COUNT(followUp.id)) > 0
  3-AND (SELECT MAX(followUp.date)) BETWEEN '201-01-01' AND '2018-12-31';

Запрос был создан с такими критериями, как:

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Service> criteriaQuery = criteriaBuilder.createQuery(Service.class);
Root<Service> from = criteriaQuery.from(Service.class);
CriteriaQuery<Service> select = criteriaQuery.select(from).distinct(Boolean.TRUE);

1-Subquery<Long> subQueryDaysTraveling = select.subquery(Long.class);
Root<ServiceItem> subQueryFromDaysTraveling = subQueryDaysTraveling.from(ServiceItem.class);
subQueryDaysTraveling.select(criteriaBuilder.function("DATEDIFF", Long.class, criteriaBuilder.least(subQueryFromDaysTraveling.<Date>get("arrivalDate")),
                                                                                  criteriaBuilder.greatest(subQueryFromDaysTraveling.<Date>get("departureDate"))));
subQueryDaysTraveling.where(criteriaBuilder.equal(from.join("serviceItens"), subQueryFromDaysTraveling));

2-Subquery<Long> subQueryAmountFollowUp = select.subquery(Long.class);
Root<FollowUp> subQueryFromAmountFollowUp = subQueryAmountFollowUp.from(FollowUp.class);
subQueryAmountFollowUp.select(criteriaBuilder.count(subQueryFromAmountFollowUp));
subQueryAmountFollowUp.where(criteriaBuilder.equal(from.join("followUp"), subQueryFromAmountFollowUp));

3-Subquery<Date> subQueryLastFollowUp = select.subquery(Date.class);
Root<FollowUp> subQueryFromLastFollowUp = subQueryLastFollowUp.from(FollowUp.class);
subQueryLastFollowUp.select(criteriaBuilder.greatest(subQueryFromLastFollowUp.<Date>get("date")));
subQueryLastFollowUp.where(criteriaBuilder.equal(from.join("followUp"), subQueryFromLastFollowUp));

...
"Simples predicates, WHERE-ANDs"
...

1-predicates.add(criteriaBuilder.and(criteriaBuilder.equal(subQueryDaysTraveling, daysTraveling)));

2-predicates.add(criteriaBuilder.and(criteriaBuilder.equal(subQueryAmountFollowUp, amountFollowUp)));

3-predicates.add(criteriaBuilder.between(subQueryLastFollowUp, lastFollowUpInitialDate, lastFollowUpFinalDate));
...
Remaining criteria
...

Подзапросы 1 и 2 работают вместе с равными внутри предиката, а с 3-го по 3-е при использовании одного и того же формата генерируется следующая ошибка:

Java.lang.ClassCastException: org.eclipse.persistence.internal.jpa.querydef.SubQueryImpl cannot be cast to org.eclipse.persistence.internal.jpa.querydef.ExpressionImpl

Еслимы изменяем предикат 3 на:

predicates.add(criteriaBuilder.between(subQueryFromLastFollowUp.<Date>get("date"), lastFollowUpInitialDate, lastFollowUpFinalDate));

Запрос сделан корректным для 1 и 2, а 3 неверен, поскольку не имеет отношения с таблицей с:

1-AND ((SELECT DATEDIFF(MIN(t6.arrival_date), MAX(t6.departure_date)) FROM service_item t6 WHERE ((t6.id_service_item = serviceItem.id_service_item) AND (t6.tenant_id = ?))) = ?))
2-AND ((SELECT COUNT(t7.id) FROM follow_up t7 WHERE ((t7.id = followUp.id) AND (t7.tenant_id = ?))) = ?)) 
3-AND (t5.date BETWEEN ? AND ?))
...