requestmapping pageable example ejemplo spring hibernate jpa spring-data pojo

pageable - Spring Data JPA asigna el resultado de la consulta nativa a POJO sin entidad



requestmapping spring boot (6)

Tengo un método de repositorio Spring Data con una consulta nativa

@Query(value = "SELECT g.*, gm.* FROM group g LEFT JOIN group_members gm ON g.group_id = gm.group_id and gm.user_id = :userId WHERE g.group_id = :groupId", nativeQuery = true) GroupDetails getGroupDetails(@Param("userId") Integer userId, @Param("groupId") Integer groupId);

y me gustaría asignar el resultado a GroupDetails POJO no de entidad.

¿Es posible y, de ser así, podría dar un ejemplo?


Creo que el enfoque de Michal es mejor. Pero, hay una forma más de obtener el resultado de la consulta nativa.

@Query(value = "SELECT g.*, gm.* FROM group g LEFT JOIN group_members gm ON g.group_id = gm.group_id and gm.user_id = :userId WHERE g.group_id = :groupId", nativeQuery = true) String[][] getGroupDetails(@Param("userId") Integer userId, @Param("groupId") Integer groupId);

Ahora, puede convertir esta matriz de cadenas 2D en su entidad deseada.


Creo que la forma más fácil de hacerlo es usar la llamada proyección. Puede asignar resultados de consultas a interfaces. Usar SqlResultSetMapping es SqlResultSetMapping y hace que su código sea feo :).

Un ejemplo del código fuente JPA de Spring Data:

public interface UserRepository extends JpaRepository<User, Integer> { @Query(value = "SELECT firstname, lastname FROM SD_User WHERE id = ?1", nativeQuery = true) NameOnly findByNativeQuery(Integer id); public static interface NameOnly { String getFirstname(); String getLastname(); } }

También puede usar este método para obtener una lista de proyecciones.

Consulte esta entrada de documentos JPA de datos de primavera para obtener más información sobre las proyecciones.

Nota 1:

Recuerde tener su entidad de User definida como normal: 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 ( getFirstname() podría devolver el valor del apellido, etc.).

Nota 2:

Si usa SELECT table.column ... notación siempre defina alias que coincidan con los nombres de la entidad. Por ejemplo, este código no funcionará correctamente (la proyección devolverá valores nulos para cada getter):

@Query(value = "SELECT user.firstname, user.lastname FROM SD_User user WHERE id = ?1", nativeQuery = true) NameOnly findByNativeQuery(Integer id);

Pero esto funciona bien:

@Query(value = "SELECT user.firstname AS firstname, user.lastname AS lastname FROM SD_User user WHERE id = ?1", nativeQuery = true) NameOnly findByNativeQuery(Integer id);

En caso de consultas más complejas, prefiero usar JdbcTemplate con un repositorio personalizado.


En mi computadora, me funciona este código. Es un poco diferente de la respuesta de Daimon.

@SqlResultSetMapping( name="groupDetailsMapping", classes={ @ConstructorResult( targetClass=GroupDetails.class, columns={ @ColumnResult(name="GROUP_ID",type=Integer.class), @ColumnResult(name="USER_ID",type=Integer.class) } ) } ) @NamedNativeQuery(name="User.getGroupDetails", query="SELECT g.*, gm.* FROM group g LEFT JOIN group_members gm ON g.group_id = gm.group_id and gm.user_id = :userId WHERE g.group_id = :groupId", resultSetMapping="groupDetailsMapping")


Puede escribir su consulta nativa o no nativa de la manera que desee, y puede ajustar los resultados de la consulta JPQL con instancias de clases de resultados personalizados. Cree un DTO con los mismos nombres de columnas devueltos en la consulta y cree un constructor de todos los argumentos con la misma secuencia y nombres devueltos por la consulta. Luego use la siguiente forma para consultar la base de datos.

@Query("SELECT NEW example.CountryAndCapital(c.name, c.capital.name) FROM Country AS c")

Crear DTO:

package example; public class CountryAndCapital { public String countryName; public String capitalName; public CountryAndCapital(String countryName, String capitalName) { this.countryName = countryName; this.capitalName = capitalName; } }


Puedes hacer algo como

@NamedQuery(name="IssueDescriptor.findByIssueDescriptorId" , query=" select new com.test.live.dto.IssuesDto (idc.id, dep.department, iss.issueName, cat.issueCategory, idc.issueDescriptor, idc.description) from Department dep inner join dep.issues iss inner join iss.category cat inner join cat.issueDescriptor idc where idc.id in(?1)")

Y debe haber un constructor como

public IssuesDto(long id, String department, String issueName, String issueCategory, String issueDescriptor, String description) { super(); this.id = id; this.department = department; this.issueName = issueName; this.issueCategory = issueCategory; this.issueDescriptor = issueDescriptor; this.description = description; }


Suponiendo GroupDetails como en la respuesta de Orid, ¿ha probado JPA 2.1 @ConstructorResult ?

@SqlResultSetMapping( name="groupDetailsMapping", classes={ @ConstructorResult( targetClass=GroupDetails.class, columns={ @ColumnResult(name="GROUP_ID"), @ColumnResult(name="USER_ID") } ) } ) @NamedNativeQuery(name="getGroupDetails", query="SELECT g.*, gm.* FROM group g LEFT JOIN group_members gm ON g.group_id = gm.group_id and gm.user_id = :userId WHERE g.group_id = :groupId", resultSetMapping="groupDetailsMapping")

y use lo siguiente en la interfaz del repositorio:

GroupDetails getGroupDetails(@Param("userId") Integer userId, @Param("groupId") Integer groupId);

De acuerdo con la documentation Spring Data JPA, Spring primero intentará encontrar una consulta con nombre que coincida con el nombre de su método, por lo que al usar @NamedNativeQuery , @SqlResultSetMapping y @ConstructorResult debería poder lograr ese comportamiento