3.1 Introducción

Otra cosa útil de la que me gustaría hablar es NativeQuery . Como ya sabe, con NativeQuery puede escribir consultas en SQL nativo. Sin embargo, lo que es aún más interesante es que no tiene que usar el mapeo de clases al obtener el resultado de la consulta.

Prefiero mostrarte un ejemplo:

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

En este ejemplo, no pasamos una clase que coincida con las filas de resultados de la consulta, sino que solo usamos una matriz de objetos Object.

Esto puede ser útil si desea seleccionar solo un par de columnas en una tabla. Ejemplo:


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

Esto es algo similar al enfoque JDBC cuando obtiene un objeto ResultSet y lee datos de sus filas.

Sin embargo, Hibernate ofrece diferentes formas de hacer esto más confiable. Por ejemplo, puede especificar el tipo de columnas que desea restar. Ejemplo:


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 Mapeo de entidades

También puede especificar explícitamente la clase que Hibernate debe usar al analizar el resultado de NativeQuery . Esto se puede hacer de diferentes maneras.


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

Y, por supuesto, el buen formato antiguo que conoces:


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

El primer enfoque es el enfoque nativo de Hibernate y el segundo es el enfoque JPA. El enfoque JPA es más conveniente y conciso, ya que este estándar se inventó después de que Hibernate existiera durante muchos años. E Hibernate evolucionó y se vio obligado a admitir enfoques antiguos para mantener la compatibilidad con sus versiones anteriores.

Por cierto, gracias a su enfoque, Hibernate le permite conectar no una clase al mapeo de resultados de la consulta, sino varias clases. Ejemplo:


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

Este enfoque que usa NativeQuery se puede usar para acelerar la selección de datos de la base de datos. Si sabe que no necesita algunas columnas, puede omitirlas en la solicitud.

También puede cargar todas las entidades secundarias a la vez, incluso si Hibernate quiere usar Cache o el mecanismo LazyLoading . Además, sus entidades secundarias pueden tener muchas columnas en la base de datos y puede seleccionar solo algunas de ellas.

3.3 Mapeo DTO

Hibernate también le permite usar clases que no son de Entidad para mapear el resultado. Clases que no tienen anotaciones y no están asignadas a ninguna tabla.

Ejemplo:

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

Dado que no hay anotaciones en la clase PersonSummaryDTO, los nombres de las columnas en la consulta SQL deben coincidir exactamente con los nombres de los campos de la clase PersonSummaryDTO.

Esto puede ser muy útil si está leyendo datos de una base de datos externa a la que su aplicación está conectada solo en modo de solo lectura. Es decir, se le dio acceso a tablas que tienen más de 50 columnas, almacenan datos en forma desnormalizada para acelerar la selección.

O digamos que alguien decidió almacenar la jerarquía de clases en una tabla, y en cinco años esta tabla ha crecido tanto que el diablo le romperá la pierna. Debe seleccionar un par de columnas de esta tabla (Id y nombre de usuario) y dárselas al cliente.

Creo que lo entiendes, pero si quieres profundizar más en este tema, puedes leer más en el enlace:

Consultas SQL nativas