JPA – Effettuare una chiamata a Stored Procedure in java

JPA – Effettuare una chiamata a Stored Procedure in java

Molto spesso occorre effettuare delle chiamate a delle stored procedures o delle funzioni sql che sono state compilate e salvate all’ interno del database utilizzato.

Per effettuare queste chiamate si possono effettuare dei semplici passi utilizzando le interfacce JPA e utilizzando EclipseLink come gestore della persistenza.

Immaginiamo di avere la seguente stored procedure, all’interno del package PCK.
Iniziamo con una stored procedure senza parametri di IN e OUT, che magari serve soltanto
a lanciare un job asincrono o che serve per contenere chiamate ad altre stored.

    
 PROCEDURE PROC_NUMBER_1()
     IS
		BEGIN
			 /*
			 .....
			 .....
			 ......
			 */
      END PROC_NUMBER_1;

Per effettuare la chiamata ad una stored procedure useremo la classe
StoredProcedureCall

	JpaEntityManager  em = creaEntityManager(......);  // recuperiamo l'entity manager tramite una funzione ad-hoc
	em.getTransaction().begin();
	StoredProcedureCall storedProcedureCall = new StoredProcedureCall();
	DataModifyQuery dataReadQuery = new DataModifyQuery();

	storedProcedureCall.setProcedureName("PCK.PROC_NUMBER_1"); // package.nnome_stored_procedure
	dataReadQuery.setCall(storedProcedureCall);

	em.getServerSession().executeQuery(dataReadQuery);

	em.close();

Come si nota dalla parte di codice di sopra, la chiamata è molto semplice, basta soltanto
specificare il nome della stored procedure e assegnarlo tramite il metodo setProcedureName().

Quando, invece, siamo in presenza di parametri di IN e di OUT cdovremo specificare nomi e valori da assegnare:

    
 PROCEDURE PROC_NUMBER_2( PARAM1 IN VARCHAR2 , PARAM2 IN NUMBER , PARAM3 OUT NUMBER)
     IS
		BEGIN
			 /*
			 .....
			 .....
			 ......
			 */
      END PROC_NUMBER_2;

Per effettuare la chiamata a questa stored procedure avremo:

  
	JpaEntityManager em = getRUNTIMEEntityManager();
	em.getTransaction().begin();

	StoredProcedureCall storedProcedureCall = new StoredProcedureCall();
	DataReadQuery dataReadQuery = new DataReadQuery();

	storedProcedureCall.setProcedureName("PCK.PROC_NUMBER_2");
	// impostiamo i parametri di ingreso tramite il loro nome
	storedProcedureCall.addNamedArgumentValue("PARAM1", new String("test"));
	storedProcedureCall.addNamedArgumentValue("PARAM2", new BigDecimal(100));
	// alternativamenre potremmo impostarli tramite il loro ordine di apparizione nella
	// chiamata a store procedure
	//  storedProcedureCall.addUnamedArgumentValue( String("test"));
	//	storedProcedureCall.addUnamedArgumentValue(new BigDecimal(100));

	// impostiamo il parametro di output
	storedProcedureCall.addNamedOutputArgument("PARAM3");
	dataReadQuery.setCall(storedProcedureCall);

	List listaDatabaseRecord = (List) em.getServerSession().executeQuery(dataReadQuery);
	// preleviamo, se esiste, l'unico record che ci restituià la stored procedure
	if (listaDatabaseRecord.size() > 0)
	{
		databaseRecord = (DatabaseRecord) listaDatabaseRecord.get(0);
		out  = new BigDecimal(databaseRecord.get("PARAM3"));
	}

Come si vede, l’esecuzione della stored procedure genererà una serie di org.eclipse.persistence.sessions.DatabaseRecord.
Ogni istanza di questa classe rappresenta un singolo record che viene recuperato, quindi potremo esaminare il
DatabaseRecord estraendo i vari campi che ci servono tramite il metodo get(nome_parametro).

Un esempio più lampante si ha quando il parametro di ritorno di una stored procedure è una serie di record prelevati dal
database:

    
 PROCEDURE PROC_NUMBER_3( PARAM1 IN VARCHAR2 , PARAM2 IN NUMBER , records OUT CURSOR)
     IS
		BEGIN

		--recuperiamo nomi , cognomi detà delle persone che vivono a roma
			OPEN retCursor FOR
			select NOME,COGNOME, ETA
			from  PERSONA
			where CITTA = "ROMA"
			;

      END PROC_NUMBER_3;

Analogamente a quanto fatto in precedenza andremo ad estrarre i vari dati da ogni DatabaseRecord hce viene restituito :

  
	JpaEntityManager em = getRUNTIMEEntityManager();
	em.getTransaction().begin();

	StoredProcedureCall storedProcedureCall = new StoredProcedureCall();
	DataReadQuery dataReadQuery = new DataReadQuery();

	storedProcedureCall.setProcedureName("PCK.PROC_NUMBER_3");

	storedProcedureCall.addNamedArgumentValue("PARAM1", new String("test"));
	storedProcedureCall.addNamedArgumentValue("PARAM2", new BigDecimal(100));

	// impostiamo il parametro di output coem un cursore
	storedProcedureCall.useNamedCursorOutputAsResultSet("PARAM3");
	dataReadQuery.setCall(storedProcedureCall);

	List listaDatabaseRecord = (List) em.getServerSession().executeQuery(dataReadQuery);
	// preleviamo, se esiste, l'unico record che ci restituià la stored procedure
	for ( i=0; i <inlistaDatabaseRecord.size() ;i++)
	{
		databaseRecord = (DatabaseRecord) listaDatabaseRecord.get(i);
		String nome  = databaseRecord.getValues("NOME").toString();
		String cognome  = databaseRecord.getValues("COGNOME").toString();
		BigDecimal eta = new BigDecimal(databaseRecord.getValues("ETA"));
	}

Abbiamo usato il metodo useNamedCursorOutputAsResultSet per impostare il parametro di uscita come un cursore, ovvero
un insieme di record che verranno esaminati.
Ciò ci permette di poter scorrere la lista di DatabaseRecord che ci viene restituita e poter prelevare i vari campi di
ogni record tramite il metodo getValues(nome_parametro).

La classe DatabaseRecord ci offre un metodo semplice per la mappatura di record di un database su liste di oggetti java
e possiede diversi metodi utili per recuperare il valore dei vari oggetti recuperati.
Analogamente, la classe StoredProcedureCall possiede diversi metodi per definire i parametri di IN, OUT o INOUT di una stored
procedure o di una funzione, ma possiede anche altri metodi utili per il filtraggio o preelaborazione dei dati che potrebbero
essere restituiti dalla stored; un esempio sono i metodi setFirstResult() e setMaxRows() che filtrano i risultatiz in modo
da restituire, ripettivamente, i record succesivi ad un certo record iniziale ed il numero massimo di righe che vogliamo
recuperare.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *