HQL 預設查詢整個實體物件,但實際往往只需部分欄位。屬性查詢(Projection) 讓你僅選取必要欄位,減少資料傳輸與物件建構開銷,提升查詢效能。本文介紹兩種寫法:陣列回傳與建構子封裝。
List list = session.createQuery(
"select user.name, user.age from TUser user").list();
Iterator it = list.iterator();
while (it.hasNext()) {
Object[] results = (Object[]) it.next();
System.out.println(results[0]); // name
System.out.println(results[1]); // age
}
回傳 List,每筆為 Object[],順序對應 SELECT 子句。
若偏好物件導向風格,可使用 new ClassName(prop1, prop2) 語法:
List list = session.createQuery(
"select new TUser(user.name, user.age) from TUser user").list();
Iterator it = list.iterator();
while (it.hasNext()) {
TUser user = (TUser) it.next();
System.out.println(user.getName());
}
public class TUser {
private String name;
private int age;
// 必須有此建構子
public TUser(String name, int age) {
this.name = name;
this.age = age;
}
// getter/setter...
}
透過建構子產生的 TUser 物件:
null/預設值saveOrUpdate()**:會導致 INSERT** 而非 UPDATE// 錯誤示範
while (it.hasNext()) {
TUser user = (TUser) it.next();
user.setName("test");
session.saveOrUpdate(user); // 產生 INSERT,非預期 UPDATE
}
可直接使用 SQL 風格彙總函數:
select count(*), min(user.age) from TUser user
select upper(user.name) from TUser user
select distinct user.name from TUser user
| 查詢方式 | 資料傳輸量 | 物件建構 | 適用場景 |
|---|---|---|---|
| 完整實體查詢 | 所有欄位 | 完整物件(含關聯) | 需完整物件圖、後續修改持久化 |
| 屬性查詢(陣列) | 僅所需欄位 | Object[] | 唯讀報表、列表頁、DTO 組裝 |
| 屬性查詢(建構子) | 僅所需欄位 | 自訂 DTO/VO | 傳遞給 View/前端、報表物件 |
Criteria criteria = session.createCriteria(TUser.class);
criteria.setProjection(Projections.projectionList()
.add(Projections.property("name"), "name")
.add(Projections.property("age"), "age"));
criteria.setResultTransformer(Transformers.aliasToBean(TUserDTO.class));
List results = criteria.list();
屬性查詢是優化 Hibernate 讀取效能的關鍵技巧。報表、列表、唯讀場景務必使用。建構子封裝雖好用,但記住:產出的物件為瞬態,不可直接持久化操作。搭配 ResultTransformer 可無縫映射至 DTO,維持乾淨架構。