JPQL查询有时不会返回预期的结果

时间:2015-01-09 00:16:35

标签: java jpa eclipselink 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 个答案:

答案 0 :(得分:0)

我不确定为什么你的查询有时会返回错误的结果(对于相同的输入?)但我认为你可以简化查询并且可能更容易调试。

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 AND
    • t.startTime是10:00,在12:00之前。
  • 活动2
    • t.endTime是11:30,大于10:00 AND
    • t.startTime是10:45,在12:00之前。