2014-09-30 14 views
5

Sto utilizzando Spring MVC 4, Hibernate e PostgreSQL 9.3 e hanno definito la funzione (stored procedure) all'interno di Postgres come questo:Come chiamare correttamente le funzioni di PostgreSQL (stored procedure) all'interno di Spring/Hibernate/JPA?

CREATE OR REPLACE FUNCTION spa.create_tenant(t_name character varying) 
    RETURNS void AS 
    $BODY$ 
    BEGIN 
     EXECUTE format('CREATE SCHEMA IF NOT EXISTS %I AUTHORIZATION postgres', t_name); 
    END 
    $BODY$ 
    LANGUAGE plpgsql VOLATILE 
    COST 100; 
ALTER FUNCTION spa.create_tenant(character varying) 
OWNER TO postgres; 

Se corro questa funzione all'interno pgAdmin come questo sta lavorando bene:

select spa.create_tenant('somename'); 

Ora sto cercando di eseguire questa funzione dal mio servizio come questo:

@Override 
@Transactional 
public void createSchema(String name) { 
    StoredProcedureQuery sp = em.createStoredProcedureQuery("spa.create_tenant"); 
    sp.registerStoredProcedureParameter("t_name", String.class, ParameterMode.IN); 
    sp.setParameter("t_name", name); 
    sp.execute(); 
} 

Se corro il mio metodo sto ottenendo seguente errore:

javax.persistence.PersistenceException: org.hibernate.MappingException: No Dialect mapping for JDBC type: 1111 

Sto indovinando questo è a causa del tipo di ritorno vuoto che viene definito in funzione così ho cambiato tipo di tornare a questo aspetto:

RETURNS character varying AS 

Se eseguo il mio metodo di nuovo mi sto questa eccezione invece:

javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Error calling CallableStatement.getMoreResults 

qualcuno sa che cosa sta succedendo qui e come chiamare correttamente stored procedure in PostgreSQL, anche con vuoto come tipo di ritorno?

+0

Come chiameresti un JDBC CallableStatement? Ecco tutto ciò che riguarda l'API JPA. Se Hibernate non rispecchia ciò che JDBC fornisce, prova un altro provider JPA per vedere come lo gestisce. –

risposta

1

Dal momento che si sta utilizzando PostgreSQL, è possibile, come si è già scritto, chiamare qualsiasi stored procedure di tipo funzione a SELECT (Oracle, in caso contrario, avrebbe permesso di eseguire solo le funzioni dichiarati leggi solo in select).

È possibile utilizzare EntityManager.createNativeQuery(SQL).

Poiché si utilizza Spring, è possibile utilizzare SimpleJdbcTemplate.query(SQL) per eseguire qualsiasi istruzione SQL.

+0

Come chiamare la funzione e ottenere il risultato sul controller? Vedi http://stackoverflow.com/q/41864288/287948 –

2

Nella classe di entità, definire un NamedNativeQuery come si chiamerebbe la funzione postgresql con select.

import javax.persistence.NamedNativeQueries; 
import javax.persistence.NamedNativeQuery; 
import javax.persistence.Entity; 
@NamedNativeQueries(
    value={ 
      // cast is used for Hibernate, to prevent No Dialect mapping for JDBC type: 1111 
      @NamedNativeQuery(
        name = "Tenant.createTenant", 
       query = "select cast(create_tenant(?) as text)" 
      ) 
    } 
) 
@Entity 
public class Tenant 

di ibernazione non è in grado di mappare vuoto, quindi una soluzione è quello di gettare risultato come testo

public void createSchema(String name) { 
    Query query = em.createNamedQuery("Tenant.createTenant") 
      .setParameter(1, name); 
    query.getSingleResult(); 
} 
+0

questa query non viene compilata –

+1

Scusa @AlexG per risposta in ritardo, ho modificato il suggerimento Codice entità, ma spero che tu abbia già trovato la soluzione – srex

1

Penso che sia la RETURN VOID che sta causando il problema. C'è an article on this topic che potrebbe aiutare pure:

CREATE OR REPLACE FUNCTION spa.create_tenant(t_name character varying) 
    RETURNS bigint AS 
    $BODY$ 
    BEGIN 
     EXECUTE format('CREATE SCHEMA IF NOT EXISTS %I AUTHORIZATION postgres', t_name); 
     RETURN 1; 
    END 
    $BODY$ 
    LANGUAGE plpgsql VOLATILE 
    COST 100; 
ALTER FUNCTION spa.create_tenant(character varying) 
OWNER TO postgres; 

Dopo aver cambiato il tuo funzione per restituire un valore fittizio, modificare la query stored procedure a questo:

StoredProcedureQuery query = entityManager 
    .createStoredProcedureQuery("spa.create_tenant") 
    .registerStoredProcedureParameter(1, 
     Long.class, ParameterMode.OUT) 
    .registerStoredProcedureParameter(2, 
     String.class, ParameterMode.IN) 
    .setParameter(2, name); 

query.getResultList(); 
+0

Come chiamare la funzione e ottieni il risultato al controller?Vedi http://stackoverflow.com/q/41864288/287948 –

Problemi correlati