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.
Другие вопросы по тегам