En este post daremos dos formas de realizar llamadas a procedimientos haciendo uso de JPA. La primera de ellas, es algo menos ortodoxa y nos servirá para hacer llamadas nativas de cualquier tipo, no solo procedimientos.
La primera forma es utilizando la anotacion '@NamedNativeQuery', que se encuentra disponible en JPA desde su primera especificación. Esta anotación te permite definir llamadas nativas sin mucha configuración, unicamente poniendole un nombre y cual va a ser la sentencia SQL Nativa. Aquí un ejemplo:
@NamedNativeQueries( { @NamedNativeQuery( name = "countColourCars", query = "CALL ASSES_PRODUCT(:color)" ) } ) @Entity @Table( name = "CAR" ) public class Car{
Para poder realizar la llamada, podemos hacerlo a través de la implementación de un DAO. Un ejemplo:
@Repository public class CarDaoImpl{ @PersistenceContext private EntityManager em; public int countColourCars( final String colour) { Query query = em.createNamedQuery( "countColourCars" ).setParameter( "colour", colour); return ((BigInteger) query.getSingleResult()).intValue(); }
Otra forma de hacerlo sería a través de la anotación '@NamedStoredProcedureQuery', la cual esta disponible a partir de la especificación JPA 2.1. Esta anotación tiene un funcionamiento similar a la anterior pero sirve solamente para procedimientos almacenados. Además tiene la particularidad de que a menos que se utilice Java 8 no puede ser repetida. Además en este ejemplo haremos uso de la antoación '@SqlResultSetMapping' que permita configurar cual va a ser la salida del procedimiento.
@StoredProcedureParameter( mode = ParameterMode.IN, type = String.class, name = "findNewsByName" ), @StoredProcedureParameter( mode = ParameterMode.IN, type = String.class, name = "orderField" ) }, resultSetMappings = "findNewsMapping" ) @SqlResultSetMapping( name = "findNewsMapping", classes = { @ConstructorResult( targetClass = New.class, columns = { @ColumnResult( name = "key", type = Integer.class ), @ColumnResult( name = "name", type = String.class ) } ) } ) @Entity @Table( name = "NEW" ) public class New{
La forma de obtener los datos es practicamente igual.
@Repository public class NewDaoImpl { @PersistenceContext private EntityManager em; @SuppressWarnings( "unchecked" ) @Override public List<New> findNewsByName( final String newsName, final String orderField ) { StoredProcedureQuery storedProcedureQuery = em.createNamedStoredProcedureQuery( "findNewsByName" ); storedProcedureQuery.setParameter( "newsName", newsName ); storedProcedureQuery.setParameter( "orderField", orderField ); storedProcedureQuery.execute(); return storedProcedureQuery.getResultList(); }
El funcionamiento es similar para ambas anotaciones, incluso también son posibles mapeos automaticos con '@NamedNativeQuery'.