3.1 簡介

我想談的另一個有用的東西是NativeQuery。如您所知,使用 NativeQuery,您可以使用本機 SQL 編寫查詢。然而,更有趣的是,您不必在獲取查詢結果時使用類映射。

我寧願給你看一個例子:

List<Object[]> persons = session.createNativeQuery("SELECT * FROM Person").list();

在這個例子中,我們沒有傳遞匹配查詢結果行的類,而是我們只使用一個 Object 對像數組。

如果您只想選擇表中的幾列,這會很有用。例子:


List<Object[]> persons = session.createNativeQuery("SELECT id, name FROM Person").list();
 
for(Object[] person : persons) {
    Number id = (Number) person[0];
    String name = (String) person[1];
}

當您獲取 ResultSet 對象並從其行中讀取數據時,這有點類似於 JDBC 方法。

然而,Hibernate 提供了不同的方法來使它更可靠。例如,您可以指定要減去的列的類型。例子:


Query<Object[]> query = session.createNativeQuery("SELECT id, name FROM Person");
query.addScalar("id", StandardBasicTypes.LONG);
query.addScalar("name", StandardBasicTypes.STRING);
List<Object[]> persons = query.list();
 
for(Object[] person : persons) {
    Long id = (Long) person[0];
    String name = (String) person[1];
}

3.2 實體映射

您還可以顯式指定 Hibernate 在解析NativeQuery的結果時應該使用的類。這可以通過不同的方式完成。


Query<Person> query = session.createNativeQuery("SELECT * FROM Person")
    .addEntity(Person.class);
    .list();

當然,你知道的好舊格式:


Query<Person> query = session.createNativeQuery("SELECT * FROM Person", Person.class).list();

第一種方法是本機 Hibernate 方法,第二種方法是 JPA 方法。JPA 方法更方便和簡潔,因為這個標準是在 Hibernate 存在多年之後發明的。Hibernate 不斷發展並被迫支持舊方法以保持與其舊版本的兼容性。

順便說一句,由於它的方法,Hibernate 允許您將多個類連接到查詢結果映射,而不是一個類。例子:


List<Phone> results = session.createNativeQuery(
    "SELECT {ph.*}, {pr.*}" +
    "FROM Phone ph" +
    "JOIN Person pr ON ph.person_id = pr.id")
.addEntity("ph", Phone.class)
.addJoin("pr", "ph.person")
.list();
 
for (Phone. phone : results) {
           	assertNotNull( phone.getPerson().getName() );
}

這種使用NativeQuery 的方法可用於加快從數據庫中選擇數據的速度。如果您知道不需要某些列,則可以在請求中將它們省略。

您還可以一次加載所有子實體,即使 Hibernate 想要使用CacheLazyLoading機制。此外,您的子實體在數據庫中可能有很多列,您只能選擇其中的一部分。

3.3 DTO映射

Hibernate 還允許您使用非實體類來映射結果。沒有任何註釋且未映射到任何表的類。

例子:

public class PersonSummaryDTO {
    private Number id;
    private String name;

    public Number getId() {
    	return id;
    }

    public void setId(Number id) {
    	this.id = id;
    }

    public String getName() {
    	return name;
    }

    public void setName(String name) {
    	this.name = name;
	}
}

List<PersonSummaryDTO> dtos = session.createNativeQuery(
    "SELECT p.id as \"id\", p.name as \"name\" FROM Person p")
.setResultTransformer(Transformers.aliasToBean(PersonSummaryDTO.class) )
.list();

由於 PersonSummaryDTO 類中沒有註釋,因此 SQL 查詢中的列名稱必須與 PersonSummaryDTO 類的字段名稱完全匹配。

如果您正在從您的應用程序僅以只讀模式連接到的外部數據庫讀取數據,這將非常有用。也就是說,您可以訪問包含 50 多個列的表,它們以非規範化形式存儲數據以加快選擇速度。

或者假設有人決定將類層次結構存儲在一張表中,五年後這張表增長得如此之大以至於魔鬼會打斷他的腿。您需要從此表中選擇幾列(Id 和用戶名)並將它們提供給客戶端。

我想你明白了,但如果你想更深入地研究這個話題,你可以在鏈接上閱讀更多內容:

本機 SQL 查詢