Estoy usando JPA en mi proyecto.
Llegué a una consulta en la que necesito hacer una operación de unión en cinco tablas. Entonces creé una consulta nativa que devuelve cinco campos.
Ahora quiero convertir el objeto de resultado a la clase de Java POJO que contiene las mismas cinco cadenas.
¿Hay alguna forma en JPA para transmitir directamente ese resultado a la lista de objetos POJO?
Llegué a la siguiente solución ...
@NamedNativeQueries({
@NamedNativeQuery(
name = "nativeSQL",
query = "SELECT * FROM Actors",
resultClass = db.Actor.class),
@NamedNativeQuery(
name = "nativeSQL2",
query = "SELECT COUNT(*) FROM Actors",
resultClass = XXXXX) // <--------------- problem
})
Ahora aquí en resultClass, ¿necesitamos proporcionar una clase que sea una entidad JPA real? O ¿Podemos convertirlo a cualquier clase de JAVA POJO que contenga los mismos nombres de columna?

Respuestas:
JPA proporciona un
SqlResultSetMappingque le permite asignar lo que devuelve su consulta nativa a una entidado una clase personalizada.EDITAR JPA 1.0 no permite la asignación a clases que no sean de entidad. Solo en JPA 2.1 se ha agregado un ConstructorResult para asignar valores de retorno a una clase java.
Además, para el problema de OP con el recuento, debería ser suficiente para definir una asignación de conjunto de resultados con un solo
ColumnResultfuente
ConstructorResultcomo uno de los parámetrosSqlResultSetMappingque permiten usar un pojo con todos los campos establecidos en el constructor. Actualizaré la respuesta.He encontrado un par de soluciones para esto.
Uso de entidades mapeadas (JPA 2.0)
Con JPA 2.0 no es posible asignar una consulta nativa a un POJO, solo se puede hacer con una entidad.
Por ejemplo:
Pero en este caso,
Jedidebe ser una clase de entidad asignada.Una alternativa para evitar la advertencia no verificada aquí sería utilizar una consulta nativa con nombre. Entonces, si declaramos la consulta nativa en una entidad
Entonces, simplemente podemos hacer:
Esto es más seguro, pero todavía estamos restringidos a usar una entidad asignada.
Mapeo manual
Una solución que experimenté un poco (antes de la llegada de JPA 2.1) fue hacer un mapeo contra un constructor POJO usando un poco de reflexión.
Básicamente, este método toma una matriz de tuplas (como la devuelven las consultas nativas) y la asigna a una clase POJO proporcionada buscando un constructor que tenga el mismo número de campos y del mismo tipo.
Entonces podemos usar métodos convenientes como:
Y simplemente podemos usar esta técnica de la siguiente manera:
JPA 2.1 con @SqlResultSetMapping
Con la llegada de JPA 2.1, podemos usar la anotación @SqlResultSetMapping para resolver el problema.
Necesitamos declarar una asignación de conjunto de resultados en algún lugar de una entidad:
Y luego simplemente hacemos:
Por supuesto, en este caso
Jedino necesita ser una entidad mapeada. Puede ser un POJO regular.Usar mapeo XML
Soy uno de los que encuentran que agregar todo esto es
@SqlResultSetMappingbastante invasivo en mis entidades, y particularmente no me gusta la definición de consultas con nombre dentro de las entidades, por lo que alternativamente hago todo esto en elMETA-INF/orm.xmlarchivo:Y esas son todas las soluciones que conozco. Los dos últimos son la forma ideal si podemos usar JPA 2.1.
fuente
@SqlResultSetMappingdebe colocarse en una entidad porque de eso JPA leerá los metadatos. No puede esperar que JPA inspeccione sus POJO. La entidad en la que coloca el mapeo es irrelevante, tal vez la que está más relacionada con sus resultados POJO. Alternativamente, la asignación podría expresarse en XML para evitar el acoplamiento con una entidad totalmente no relacionada.@SqlResultSetMappingél, vale la pena señalar que laJediclase requerirá un constructor todo arg y la@ColumnResultanotación puede necesitar que setypeagregue el atributo a las conversiones que podrían no ser implícitas (necesitaba agregartype = ZonedDateTime.classalgunas columnas).Sí, con JPA 2.1 es fácil. Tienes anotaciones muy útiles. Simplifican tu vida.
Primero declare su consulta nativa, luego su asignación de conjunto de resultados (que define la asignación de los datos devueltos por la base de datos a sus POJO). Escriba su clase de POJO para referirse (no se incluye aquí por brevedad). Por último, pero no menos importante: cree un método en un DAO (por ejemplo) para llamar a la consulta. Esto funcionó para mí en una aplicación dropwizard (1.0.0).
Primero declare una consulta nativa en una clase de entidad:
Debajo puede agregar la declaración de mapeo del conjunto de resultados:
Más adelante en un DAO puede referirse a la consulta como
Eso es.
fuente
Si lo usa
Spring-jpa, este es un complemento de las respuestas y esta pregunta. Corrija esto si hay fallas. Principalmente he usado tres métodos para lograr el "resultado de mapeoObject[]a un pojo" basado en la necesidad práctica que cumplo:sqlcon suEntityes suficienteLos primeros 2 fallaron, y tengo que usar a
nativeQuery. Aquí están los ejemplos. El pojo esperaba:Método 1 : cambie el pojo a una interfaz:
Y repositorio:
Método 2 : repositorio:
Nota: la secuencia de parámetros del constructor POJO debe ser idéntica tanto en la definición POJO como en sql.
Método 3 : Uso
@SqlResultSetMappingy@NamedNativeQueryen laEntityque el ejemplo de la respuesta de Edwin Dalorzo.Los primeros dos métodos llamarían a muchos manejadores intermedios, como convertidores personalizados. Por ejemplo,
AntiStealingdefine asecretKey, antes de que persista, se inserta un convertidor para encriptarlo. Esto daría como resultado que los primeros 2 métodos devuelvan una conversión convertidasecretKeyque no es lo que quiero. Si bien el método 3 superaría el convertidor, y se devolveríasecretKeysería el mismo que se almacena (uno cifrado).fuente
El procedimiento de desenvoltura se puede realizar para asignar resultados a entidades que no sean entidades (que es Beans / POJO). El procedimiento es el siguiente.
El uso es para la implementación JPA-Hibernate.
fuente
JobDTOdebe tener un constructor predeterminado. O puede implementar su propio transformador basado en laAliasToBeanResultTransformerimplementación.Primero declare las siguientes anotaciones:
Luego anote su POJO de la siguiente manera:
Luego escriba el procesador de anotaciones:
Use el marco anterior de la siguiente manera:
fuente
BeanUtils?La forma más fácil es usar las proyecciones . Puede asignar resultados de consultas directamente a las interfaces y es más fácil de implementar que usar SqlResultSetMapping.
A continuación se muestra un ejemplo:
Los campos de la interfaz proyectada deben coincidir con los campos de esta entidad. De lo contrario, la asignación de campo podría romperse.
Además, si usa la
SELECT table.columnnotación, siempre defina alias que coincidan con los nombres de la entidad, como se muestra en el ejemplo.fuente
En hibernación, puede usar este código para asignar fácilmente su consulta nativa.
fuente
Usando Hibernate:
fuente
Estilo antiguo con ResultSet
fuente
Como otros ya han mencionado todas las soluciones posibles, estoy compartiendo mi solución alternativa.
En mi situación con
Postgres 9.4, mientras trabajo conJackson,Estoy seguro de que puede encontrar lo mismo para otras bases de datos.
También para su información, resultados de consultas nativas JPA 2.0 como mapa
fuente
No estoy seguro de si esto encaja aquí, pero tuve una pregunta similar y encontré la siguiente solución / ejemplo simple para mí:
En mi caso, tuve que usar las partes SQL definidas en cadenas en otro lugar, por lo que no pude usar NamedNativeQuery.
fuente
Estilo antiguo con Resultset
fuente
Hemos resuelto el problema de la siguiente manera:
fuente
Vea el siguiente ejemplo para usar un POJO como pseudoentidad para recuperar el resultado de una consulta nativa sin usar SqlResultSetMapping complejo. Solo necesito dos anotaciones, una @Enity desnuda y una @Id ficticia en tu POJO. @Id se puede usar en cualquier campo de su elección, un campo @Id puede tener claves duplicadas pero no valores nulos.
Como @Enity no se asigna a ninguna tabla física, este POJO se denomina pseudoentidad.
Entorno: eclipselink 2.5.0-RC1, jpa-2.1.0, mysql-connector-java-5.1.14
Puedes descargar el proyecto completo de Maven aquí
La consulta nativa se basa en ejemplos de empleados de MySQL db http://dev.mysql.com/doc/employee/en/employees-installation.html
persistence.xml
Employee.java
EmployeeNativeQuery.java
fuente
listes, supuestamente, una lista deEmployee, ¿por qué su ciclo for-each itera sobre un tipoObject? Si escribe su ciclo for-each comofor(Employee emp : list)entonces, descubriría que su respuesta es incorrecta y que el contenido de su lista no son empleados y que esa advertencia que suprimió tenía el propósito de alertarlo sobre este posible error.List<Employee> list = (List<Employee>) query.getResultList();Cambiarfor (Object emp : list)afor (Employee emp : list)es mejor, pero no hay errores si se mantieneObject empya que la lista es una instancia deList<Employee>. Cambié el código en el proyecto git pero no aquí para mantener tu comentario relevante a la publicación originalQuery query = em.createNativeQuery("select * ...", Employee.class);y persistence.xml, la consulta nativa devuelve una lista de Empleado. Acabo de salir y ejecutar el proyecto sin problema. Si configura los empleados de muestra de MySQL DB localmente, también debería poder ejecutar el proyectoEmployeelo que supongo que es una entidad. ¿No es así?si está usando Spring, puede usar
org.springframework.jdbc.core.RowMapperAquí hay un ejemplo:
fuente
Usando Hibernate:
fuente
Manera simple de convertir la consulta SQL a la colección de clase POJO,
fuente
Todo lo que necesitas es un DTO con un constructor:
y llámalo:
fuente
Uso
DTO Design Pattern. Fue utilizado enEJB 2.0. La entidad fue administrada por contenedor.DTO Design Patternse utiliza para resolver este problema Pero, podría usarse ahora, cuando la aplicación se desarrolleServer Sidey porClient Sideseparado.DTOse usa cuandoServer sideno quiere pasar / regresarEntitycon anotación aClient Side.Ejemplo de DTO:
PersonEntity.java
PersonDTO.java
DTOBuilder.java
EntityBuilder.java <- puede ser necesario
fuente