Solución:
Creo que la forma más sencilla de hacerlo es utilizar la llamada proyección. Puede asignar resultados de consultas a interfaces. Utilizando SqlResultSetMapping
es incómodo y hace que su código sea feo :).
Un ejemplo directamente 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 utilizar 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:
Recuerda tener tu User
entidad definida como normal: los campos de la interfaz proyectada deben coincidir con los campos de esta entidad. De lo contrario, el mapeo de campo podría romperse (getFirstname()
podría devolver el valor del apellido, etc.).
Nota 2:
Si utiliza SELECT table.column ...
la notación siempre define los alias que coinciden con los nombres de la entidad. Por ejemplo, este código no funcionará correctamente (la proyección devolverá nulos para cada captador):
@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 su lugar.
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 documentación de Spring Data JPA, Spring primero intentará encontrar una consulta con nombre que coincida con el nombre de su método, por lo que debe usar @NamedNativeQuery
, @SqlResultSetMapping
y @ConstructorResult
deberías poder lograr ese comportamiento
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.