上圖兩個 table 是一對多的關係,要查詢出飯局的地點在那一個餐廳,及餐廳的相關資料,可以用之前介紹過的一對多方式 …
這篇要說明的是另一種方式,這個方式在三個或三個以上 table join 時,特別有用。假設我們要傳回的欄位如下:
1 @Entity
2 @Data
3 public class AppointmentDetail {
4 private String email; //電子郵件
5 private String name; //飯局名稱
6 private String restaurantName; //餐廳名稱
7 private String restaurantAddr; //餐廳地址
8 private String description; //飯局說明
9 private int people; //參與人數
10 private int willPay; //消費額
11 private Date htime; //舉辦時間
12
13 @Id
14 private Long sysId; //序號
15 }
如上的類別 AppointmentDetail 包含了兩個 table 的欄位,這個類別一樣要用 @Entity 標示,且也要用 @Id 標示可成為唯一的欄位,特別說明的是第 2 行的 @Data,這和 JPA 或 Spring 無關,這是
Lombok 提供的功能,用來簡化程式設計,在這邊加上 @Data 就可以為類別裡所有的欄位 (field) 加上 getter、setter method,這解決了程式設計人員老是在 POJO 中廢時寫 getter、setter 的困擾。
接著在 DAO 中增加一個 method 如下,寫法沒什麼特別,只是傳回結果擁有兩個 table 的欄位。
1 public AppointmentDetail find(Long sysId) {
2 Query query = manager.createNativeQuery(
3 " select a.email, a.name, r.name restaurantName, r.address restaurantAddr, a.description, a.people, a.willPay, a.htime, a.sysId "
4 + "from appointment a inner join restaurant r on a.restaurant_sysid = r.sysId where a.sysId = :sysId "
5 , AppointmentDetail.class);
6 query.setParameter("sysId", sysId);
7 return (AppointmentDetail) query.getSingleResult();
8 }
測試程式如下,當然也和之前寫過的使用 DAO 的方式沒什麼不一樣。
1 @Transactional
2 @Test
3 public void testFindDetail() {
4 AppointmentDetail detail = daoApp.find(12L);
5 assertNotNull(detail);
6 System.out.println(detail.toString());
7 }
總結來說,唯一的不同在於 @Entity 類別,在那個類別中,不需要使用 @Table 來指出是屬於資料庫裡的那個 table。
另外,在 spring data 中提供另一種更簡潔的寫法,只要寫一個介面,繼承 Repository 或它的子介面 (
CrudRepository、
PagingAndSortingRepository、RevisionRepository),可以直接在 method 上寫 sql,如下:
public interface AppointmentDetailDAO extends Repository<AppointmentDetail, Long> {
@Query(value="select a.email, a.name, r.name as restaurantName, r.address as restaurantAddr, a.description, a.people, a.willPay, a.htime, a.sysId from Appointment a inner join Restaurant r on a.restaurant_sysId = r.sysId where a.sysId = :sysId", nativeQuery=true)
public AppointmentDetail findDetailBySysId(@Param("sysId") Long sysId);
}
這裡要注意的是,AppointmentDetail 是複合型別,只能用 native query (nativeQuery 預設值為 false),不能用 JPQL,否則會有無法轉換型別的錯誤訊息「org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.Object[]] to type …」。
【Lombok 的使用】
- 從官網上下載 lombok.jar,將它放在 eclipse.ini 所在的目錄裡。
- 在 eclipse.ini 中加入如下內容:
-Xms2048m
-Xmx4096m
-javaagent:lombok.jar
- 重啟 eclipse。