2017-02-14 15 views
10

У меня есть следующий родной SQL запрос, который я пытаюсь преобразовать критерии JPA:Преобразование SQL левое внешнее соединение запроса к JPA Критерии

select et.* from t_empl_tx et, t_dept d 
where et.assigned_dept = d.dept (+) 
    and et.employee_id = :employee_id 
    and (et.start_date >= d.dept_est_date and 
     et.start_date <= d.dept_close_date or 
     et.start_date is null or 
     d.dept is null) 

(Заметим, что (+) примерно эквивалентно левого внешнего присоединяйтесь в этом случае. Да, я знаю, что это означает OPTIONAL table и т. д. и т. д.).

Вот моя попытка кода:

EntityManager entityManager = getEntityManager(); 
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); 
CriteriaQuery<EmployeeTransaction> criteriaQuery = criteriaBuilder.createQuery(EmployeeTransaction.class); 
Root<EmployeeTransaction> root = criteriaQuery.from(EmployeeTransaction.class); 

    // this line bombs! 
Join<EmployeeTransaction, Department> join = 
    root.join(EmployeeTransaction_.assignedDepartment).join(Department_.id).join(DepartmentCompositeId_.department, JoinType.LEFT); 

List<Predicate> predicates = new ArrayList<>(); 

predicates.add(criteriaBuilder.equal(root.get(EmployeeTransaction_.id).get(EmployeeTransactionCompositeId_.employeeId), employeeId)); 
predicates.add(criteriaBuilder.or(
    criteriaBuilder.and(
    criteriaBuilder.greaterThanOrEqualTo(root.<Date>get(EmployeeTransaction_.requestedStartDate), join.get(Department_.id).<Date>get(DepartmentCompositeId_.departmentCreationDate)), 
    criteriaBuilder.lessThanOrEqualTo(root.<Date>get(EmployeeTransaction_.requestedStartDate), join.<Date>get(Department_.departmentCloseDate)) 
    ), 
    criteriaBuilder.isNull(root.get(EmployeeTransaction_.requestedStartDate)), 
    criteriaBuilder.isNull(join.get(Department_.id).get(DepartmentCompositeId_.departmentCreationDate)) 
)); 

criteriaQuery.select(root).where(predicates.toArray(new Predicate[]{})); 

TypedQuery<EmployeeTransaction> query = entityManager.createQuery(criteriaQuery); 
List<EmployeeTransaction> result = query.getResultList(); 

Этот вопрос, кажется, что я пытаюсь присоединиться строковый столбец, assigedDepartment, к одному полю составного идентификатора. Это совершенно законно в SQL, но не так просто в коде.

Один из вариантов заключается в том, чтобы преобразовать в число подзапросов, которые, кажется, полностью уничтожают точку левого внешнего соединения.

Может ли кто-нибудь указать, что я делаю неправильно?

Jason

+0

Нет времени, чтобы написать ответ, но " выберите entity1 из entity1 left join entity1.field2 где ... ". Если вы хотите, чтобы левое соединение было с нетерпением, вам нужно иметь «левую вставку». –

+0

Атрибут JoinType имеет только три возможных значения: INNER, LEFT и RIGHT. Кажется, что нет опции для левого соединения. Кроме того, в строке join() есть что-то не так. Несмотря на то, что join() возвращает SingularAttribute <>, я, похоже, не могу сгруппировать такие команды. – Jason

+1

В запросе по критериям JPA вы ссылаетесь на таблицу 'DepartmentCompositeId', которая отсутствует в запросе SQL. Пожалуйста, заполните эту информацию, добавив соответствующие части определения каждого объекта. – perissf

ответ

2

Вы должны размещать свои объекты таким образом, чтобы ответы на них могут быть более конкретными.

Однако, я попробую.

Если я прав, вы можете переписать запрос:

select et.* 
from t_empl_tx et 
    left join t_dept d on et.assigned_dept = d.dept 
where 
    et.employee_id = :employee_id 
    and (
     et.start_date >= d.dept_est_date 
     and et.start_date <= d.dept_close_date 
     or et.start_date is null 
     or d.dept is null) 

Так, в скором времени, вы должны переместить JoinType.LEFT к assignedDepartment не присоединиться:

EntityManager entityManager = getEntityManager(); 
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); 
CriteriaQuery<EmployeeTransaction> criteriaQuery = criteriaBuilder.createQuery(EmployeeTransaction.class); 

Root<EmployeeTransaction> root = criteriaQuery.from(EmployeeTransaction.class); 
Join<EmployeeTransaction, Department> department = root.join(EmployeeTransaction_.assignedDepartment, JoinType.LEFT); 
Path<Date> employeeTransactionRequestedStartDate = root.get(EmployeeTransaction_.requestedStartDate); 
Path<DepartmentCompositeId> departmentId = department.get(Department_.id); 
Path<Date> departmentCreationDate = departmentId.get(DepartmentCompositeId_.departmentCreationDate) 
Path<Date> departmentCloseDate = departmentId.get(DepartmentCompositeId_.departmentCloseDate) 

criteriaQuery.select(root).where(
    criteriaBuilder.equal(root.get(EmployeeTransaction_.id).get(EmployeeTransactionCompositeId_.employeeId), employeeId), 
    criteriaBuilder.or(
     criteriaBuilder.and(
      criteriaBuilder.greaterThanOrEqualTo(employeeTransactionRequestedStartDate, departmentCreationDate)), 
      criteriaBuilder.lessThanOrEqualTo(employeeTransactionRequestedStartDate, departmentCloseDate) 
     ), 
     criteriaBuilder.isNull(employeeTransactionRequestedStartDate), 
     criteriaBuilder.isNull(departmentCreationDate) 
    ) 
); 

TypedQuery<EmployeeTransaction> query = entityManager.createQuery(criteriaQuery); 
List<EmployeeTransaction> result = query.getResultList();