3.1 Giới thiệu

Một điều hữu ích khác mà tôi muốn nói đến là NativeQuery . Như bạn đã biết, sử dụng NativeQuery, bạn có thể viết các truy vấn bằng SQL gốc. Tuy nhiên, điều thú vị hơn nữa là bạn không phải sử dụng ánh xạ lớp khi nhận kết quả truy vấn.

Tôi muốn chỉ cho bạn một ví dụ:

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

Trong ví dụ này, chúng tôi không chuyển một lớp khớp với các hàng kết quả truy vấn, thay vào đó chúng tôi chỉ sử dụng một mảng các đối tượng Object.

Điều này có thể hữu ích nếu bạn chỉ muốn chọn một vài cột trong bảng. Ví dụ:


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];
}

Điều này hơi giống với cách tiếp cận của JDBC khi bạn lấy một đối tượng ResultSet và đọc dữ liệu từ các hàng của nó.

Tuy nhiên, Hibernate cung cấp các cách khác nhau để làm cho điều này trở nên đáng tin cậy hơn. Ví dụ: bạn có thể chỉ định loại cột bạn muốn trừ. Ví dụ:


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 Ánh xạ thực thể

Bạn cũng có thể chỉ định rõ ràng lớp mà Hibernate sẽ sử dụng khi phân tích cú pháp kết quả của NativeQuery . Điều này có thể được thực hiện theo những cách khác nhau.


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

Và tất nhiên, định dạng cũ tốt mà bạn biết:


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

Cách tiếp cận đầu tiên là cách tiếp cận Hibernate riêng và cách thứ hai là cách tiếp cận JPA. Cách tiếp cận JPA thuận tiện và ngắn gọn hơn, vì tiêu chuẩn này được phát minh sau khi Hibernate tồn tại trong nhiều năm. Và Hibernate đã phát triển và buộc phải hỗ trợ các phương pháp cũ để duy trì khả năng tương thích với các phiên bản cũ của nó.

Nhân tiện, nhờ cách tiếp cận của nó, Hibernate cho phép bạn kết nối không phải một lớp với ánh xạ kết quả truy vấn mà là một số lớp. Ví dụ:


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() );
}

Cách tiếp cận sử dụng NativeQuery này có thể được sử dụng để tăng tốc độ lựa chọn dữ liệu từ cơ sở dữ liệu. Nếu bạn biết rằng bạn không cần một số cột, bạn có thể loại bỏ chúng trong yêu cầu.

Bạn cũng có thể tải tất cả các thực thể con cùng một lúc, ngay cả khi Hibernate muốn sử dụng Cache hoặc cơ chế LazyLoading . Ngoài ra, các thực thể con của bạn có thể có nhiều cột trong cơ sở dữ liệu và bạn chỉ có thể chọn một số trong số chúng.

3.3 Ánh xạ DTO

Hibernate cũng cho phép bạn sử dụng các lớp không phải Thực thể để ánh xạ kết quả. Các lớp không có bất kỳ chú thích nào và không được ánh xạ tới bất kỳ bảng nào.

Ví dụ:

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();

Vì không có chú thích nào trong lớp PersonSummaryDTO nên tên của các cột trong truy vấn SQL phải khớp chính xác với tên của các trường trong lớp PersonSummaryDTO.

Điều này có thể rất hữu ích nếu bạn đang đọc dữ liệu từ cơ sở dữ liệu bên ngoài mà ứng dụng của bạn chỉ được kết nối ở chế độ chỉ đọc. Nghĩa là, bạn được cấp quyền truy cập vào các bảng có hơn 50 cột, chúng lưu trữ dữ liệu ở dạng không chuẩn hóa để tăng tốc độ lựa chọn.

Hoặc giả sử rằng ai đó đã quyết định lưu trữ hệ thống phân cấp lớp trong một bảng, và trong 5 năm, bảng này đã phát triển đến mức ma quỷ sẽ làm gãy chân anh ta. Bạn cần chọn một vài cột từ bảng này (Id và tên người dùng) và đưa chúng cho khách hàng.

Tôi nghĩ bạn hiểu, nhưng nếu bạn muốn tìm hiểu sâu hơn về chủ đề này, bạn có thể đọc thêm tại liên kết:

Truy vấn SQL gốc