2020年7月19日 星期日

LEFT OUTER JOIN

本文為【Spring Boot情境式網站開發指南:使用Spring Data JPA、Spring Security、Spring Web Flow】一書的【 第4章 Criteria API入門】延續,完整範例程式碼可至出版社下載

使用LEFT OUTER JOIN並擷取Employee所有欄位

當JPQL使用以下語句時:
  1. SELECT DISTINCT e FROM Employee e
  2. LEFT OUTER JOIN e.tasks t
對應的Criteria API用法如下:
  1. @Test
  2. public void Criteria_LeftJoin1() {
  3. EntityManager em = emf.createEntityManager();
  4. CriteriaBuilder cb = em.getCriteriaBuilder();
  5. CriteriaQuery sql = cb.createQuery(Employee.class);
  6. Root emp = sql.from(Employee.class);
  7. emp.join(Employee_.tasks, JoinType.LEFT);
  8. sql.select(emp)
  9. .distinct(true);
  10. TypedQuery typedQuery = em.createQuery(sql);
  11. List resultList = typedQuery.getResultList();
  12. resultList.forEach(System.out::println);
  13. assertThat(resultList, containsInAnyOrder(
  14. employee1, employee2,
  15. employee3, employee4));
  16. assertThat(resultList, hasSize(4));
  17. }
說明:
  • 行7:
emp.join(Employee_.tasks, JoinType.LEFT);等價於Employee e LEFT OUTER JOIN e.tasks t。方法join()未指定JoinType時預設為JoinType.INNER。本例為LEFT JOIN,需指定JoinType.LEFT。

使用LEFT OUTER JOIN擷取Employee的name與Task的description欄位

承前例,但查詢的欄位改為「e.name, t.name」。當JPQL使用以下語句時:
  1. SELECT DISTINCT e.name, t.name
  2. FROM Employee e
  3. LEFT OUTER JOIN e.tasks t
對應的Criteria API用法如下:
  1. @Test
  2. public void Criteria_LeftJoin2() {
  3. EntityManager em = emf.createEntityManager();
  4. CriteriaBuilder cb = em.getCriteriaBuilder();
  5. CriteriaQuery sql = cb.createTupleQuery();
  6. Root emp = sql.from(Employee.class);
  7. Join task = emp.join(Employee_.tasks, JoinType.LEFT);
  8. // task.on(cb.equal(task.get(Task_.name), "Denise"));
  9. sql.select(cb.tuple(emp.get(Employee_.name).alias("employeeName"),
  10. task.get(Task_.name).alias("supervisor")))
  11. .distinct(true);
  12. TypedQuery typedQuery = em.createQuery(sql);
  13. List resultList = typedQuery.getResultList();
  14. List rows = resultList.stream()
  15. .map(t -> t.get("employeeName", String.class) + ", " +
  16. t.get("supervisor", String.class))
  17. .collect(Collectors.toList());
  18. rows.forEach(System.out::println);
  19. em.close();
  20. assertThat(rows, containsInAnyOrder(
  21. "Tim, Mike",
  22. "Tim, Denise",
  23. "Mike, Rose",
  24. "Mike, Mike",
  25. "Jim, Denise",
  26. "Jack, null"));
  27. assertThat(rows, hasSize(6));
  28. /*
  29. assertThat(rows, containsInAnyOrder(
  30. "Jim, Denise",
  31. "Jack, null",
  32. "Mike, null",
  33. "Tim, Denise"));
  34. assertThat(rows, hasSize(4));
  35. */
  36. }
說明:

  • 行7:
因為必須查詢聯結表格Task的欄位,因此建立Join<Employee, Task> task的物件參考指向join()方法執行結果。
  • 行8:
可以藉由Join<Employee, Task> task的on()方法限定對聯結表格Task的查詢條件,對應的JPQL子句為「LEFT OUTER JOIN e.tasks t ON t.name='Denise'」。本行若取消comment,將改得到行29-34的結果;或改執行單元測試方方法Criteria_LeftJoinOn()驗證結果。
  • 行10:
指定要查詢Task的name欄位。

沒有留言:

張貼留言