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 엔터티 매핑

NativeQuery 의 결과를 구문 분석할 때 Hibernate가 사용해야 하는 클래스를 명시적으로 지정할 수도 있습니다 . 이것은 다른 방법으로 수행될 수 있습니다.


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가 Cache 또는 LazyLoading 메커니즘 을 사용하기를 원하는 경우에도 한 번에 모든 자식 엔터티를 로드할 수 있습니다 . 또한 하위 엔터티에는 데이터베이스에 많은 열이 있을 수 있으며 그 중 일부만 선택할 수 있습니다.

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개 이상의 열이 있는 테이블에 대한 액세스 권한이 부여되었으며 선택 속도를 높이기 위해 비정규화된 형식으로 데이터를 저장합니다.

또는 누군가가 하나의 테이블에 클래스 계층 구조를 저장하기로 결정했는데 5년 만에 이 테이블이 너무 커져서 악마가 그의 다리를 부러뜨릴 것이라고 가정해 보겠습니다. 이 테이블에서 몇 개의 열(Id 및 사용자 이름)을 선택하여 클라이언트에 제공해야 합니다.

이해하셨겠지만 이 주제에 대해 더 자세히 알아보고 싶다면 다음 링크에서 자세한 내용을 읽을 수 있습니다.

네이티브 SQL 쿼리