JPQL-запрос иногда не возвращает ожидаемый результат
У меня странная проблема с JPQL-запросом, демонстрирующим некоторое противоречивое поведение. Я написал следующий метод, из которого я ожидаю получить список всех действий для данного сотрудника, которые перекрывают данный объект TimePeriod.
public List<Activity> getAllActivities(Employee employee,
TimePeriod timePeriod) throws DatasetException {
if (employee == null || timePeriod == null) {
throw new IllegalArgumentException();
}
try {
final Query query = em
.createQuery("SELECT DISTINCT a from Activity a INNER JOIN a.employeeTimePeriods e"
+ " INNER JOIN e.timePeriods t WHERE "
+ " e.employee = ?1"
+ " AND a.time.day = ?2"
+ " AND ?3 < t.endTime"
+ " AND ?4 > t.startTime"
+ " ORDER BY a.time.startTime");
query.setParameter(1, employee);
query.setParameter(2, timePeriod.getDay());
query.setParameter(3, timePeriod.getStartTime());
query.setParameter(4, timePeriod.getEndTime());
return query.getResultList();
} catch (Exception e) {
LOGGER.error(String.format(
"Exception while getting all activities of employee %s, "
+ "which overlap time period %s.", employee,
timePeriod), e);
throw new DatasetException(
String.format(
"Error while getting all activities of employee %s, "
+ "which overlap time period %s: "
+ e.getMessage(), employee, timePeriod));
}
}
Кроме того, я создал несколько тестовых случаев: у меня есть один сотрудник, который участвует в двух видах деятельности:
- Понедельник с 10:00 до 10:45
- Понедельник с 10:45 до 11:30
И у меня есть объект TimePeriod с днем, установленным на понедельник, временем начала, установленным на 10:00, и временем окончания, установленным на 12:00.
Теперь я ожидаю, что всегда получу оба ранее перечисленных вида деятельности из моего метода, но есть проблема. Я иногда (!) Получаю только первое, в других случаях тестирование проходит успешно. У меня есть еще несколько тестов для этого метода, которые никогда не заканчивались (но я только что заметил, что приведенный выше тест является единственным, который должен выбрать два действия).
У меня также есть такой же тестовый пример для комнат (за исключением того, что время начала объекта TimePeriod там 09:00), который никогда не заканчивался. Но из-за разницы в запросах - в запросе номеров я смог использовать MEMBER OF
- Я предполагаю, что могут быть проблемы с соединениями.
Для полноты изложения запрос на номера:
final Query query = em.createQuery("SELECT a FROM Activity a WHERE"
+ " ?1 MEMBER OF a.rooms AND a.time.day = ?2"
+ " AND ?3 < a.time.endTime AND ?4 > a.time.startTime"
+ " ORDER BY a.time.startTime");
query.setParameter(1, room);
query.setParameter(2, timePeriod.getDay());
query.setParameter(3, timePeriod.getStartTime());
query.setParameter(4, timePeriod.getEndTime());
У кого-нибудь есть предложения относительно решения моей проблемы?
1 ответ
Я не уверен, почему ваш запрос иногда возвращает неправильные результаты (для одних и тех же входных данных?), Но я думаю, что вы могли бы упростить запрос и, возможно, легче отладить его.
select
distinct a
from
Activity a inner join a.employeeTimePeriods e
inner join e.timePeriods t
where
e.employee = ?1 and
a.time.day = ?2 and
t.endTime >= ?3 and
t.startTime <= ?4
Где?1 = комната,?2 = день,?3 = время начала и?4 = время окончания.
По сути, вы просите: "Покажите мне действия для конкретного сотрудника в данный день, которые заканчиваются после или в моем окне запуска и запускаются до или в конце моего окна.
Итак, для вашей деятельности:
- Занятие 1 = понедельник с 10:00 до 10:45
- Занятие 2 = понедельник с 10:45 до 11:30
И период времени: с 10:00 до 12:00, он должен возвратить обе эти записи, потому что:
- Деятельность 1
- t.endTime - 10:45, что больше 10:00 И
- t.startTime - 10:00 и до 12:00.
- Деятельность 2
- t.endTime - 11:30, что больше 10:00 И
- t.startTime - 10:45 и до 12:00.