Eseguire una Funzione di oracle che restituisce un riferimento cursore in C#

Ho un pacchetto di oracle con una procedura che ha un in riferimento cursore. La mia comprensione è che questo è abbastanza standard.

Quello che non mi piace è il fatto che ho dovuto scrivere un sacco di codice per vedere appena uscita. Così ho chiesto a questa domanda e si può ottenere quello che voglio con la creazione di una funzione che avvolge la procedura.

Aggiornamento: Sembra non ho bisogno di funzionare, ma potrebbe essere la pena di conoscere, comunque, per chi è curioso di vedere l’originale di domanda e risposta aggiornamenti.

Ecco la funzione

FUNCTION GetQuestionsForPrint (user in varchar2)
  RETURN MYPACKAGE.refcur_question
AS  

    OUTPUT MYPACKAGE.refcur_question;

BEGIN 

      MYPACKAGE.GETQUESTIONS(p_OUTPUT => OUTPUT, 
      p_USER=> USER ) ;


  RETURN OUTPUT;
END;

ed ecco cosa posso fare per eseguire in SQL Developer

var r refcursor;
exec :r := mypackage.getquestionsForPrint('OMG Ponies');
print r;

Ora io sono probabilmente andando ad aggiungere il ForPrint funzioni a tutte le mie procedure.

Questo mi ha fatto pensare che, forse, le funzioni sono quello che voglio e non ho bisogno di procedure.

Per testare questo ho cercato di eseguire la funzione .NETTO, a meno che io non posso farlo. È davvero questo il modo in cui è.

using (OracleConnection cnn = new OracleConnection("Data Source=Test;User Id=Test;Password=Test;"))
{
    cnn.Open();
    OracleCommand cmd = new OracleCommand("mypackage.getquestionsForPrint");
    cmd.CommandType = System.Data.CommandType.StoredProcedure;

    cmd.Parameters.Add ( "p_USER", "OMG Ponies");

    cmd.Connection = cnn;
    OracleDataReader rdr = cmd.ExecuteReader();

    while (rdr.Read())
    {
        Console.WriteLine(rdr.GetOracleValue(0));
    }

    Console.ReadLine();
}

Così ottengo l’errore.

getquestionsForPrint is not a procedure or is undefined

Ho provato ExecuteScalar e con lo stesso risultato.

MODIFICA Prendendo Slider345 i consigli ho provato anche impostando il tipo di comando di testo e utilizzando la seguente istruzione e ottengo
istruzione SQL non valida

mypackage.getquestionsForPrint('OMG Poinies');

e

var r refcursor; exec :r :=  mypackage.getquestionsForPrint('OMG Poinies'); 

Utilizzando Abhi variazione per il comando di testo

select mypackage.getquestionsForPrint('OMG Poinies') from dual

ha portato

L’istruzione a “0x61c4aca5”
ha fatto riferimento alla memoria a “0x00000ce1”. Il
memoria non poteva essere “read”.

Sono solo abbaiare contro l’albero sbagliato?

Aggiornamento
Il tentativo di aggiungere un parametro di output non aiuta.

cmd.Parameters.Add(null, OracleDbType.RefCursor, ParameterDirection.Output);

Non sicuro di quello che il nome dovrebbe essere dalla sua il valore di ritorno di una funzione (ho provato null, stringa vuota, mypackage.getquestionsForPrint), ma in tutti i casi esso solo risultati nella

ORA-06550: riga 1, colonna 7:
PLS-00306: numero sbagliato o tipi di
argomenti nella chiamata a
‘getquestionsForPrint’

Modifica definitiva (si spera)

Apparentemente Guddie chiesto un domanda simile 3 mesi dopo di me. Ha avuto la risposta che è

  • Impostare il comando testo di un anonimo blocco
  • Associare un parametro ref cursor impostazione della direzione di uscita
  • Chiamata Eseguire non lettore.
  • Quindi utilizzare il parametro

using (OracleConnection cnn = new OracleConnection("Data Source=Test;User Id=Test;Password=Test;"))
{
    cnn.Open();
    OracleCommand cmd = new OracleCommand("mypackage.getquestionsForPrint");
    cmd.CommandType = CommandType.Text;

    cmd.CommandText = "begin " +
              "    :refcursor1 := mypackage.getquestionsForPrint('OMG Ponies') ;"  +
              "end;";

    cmd.Connection = cnn;
    OracleDataAdapter da = new OracleDataAdapter(cmd);
    cmd.ExecuteNonQuery();

    Oracle.DataAccess.Types.OracleRefCursor t = (Oracle.DataAccess.Types.OracleRefCursor)cmd.Parameters[0].Value;
    OracleDataReader rdr = t.GetDataReader();
    while(rdr.Read())
        Console.WriteLine(rdr.GetOracleValue(0));

    Console.ReadLine();
}
  • Nessuna tale cosa come un “racleCommand”, post codice vero e proprio.
  • mi dispiace persa per copiare in qualche modo
  • Conrad, non avete bisogno di un wrapper – ho aggiornato la precedente domanda. Non conosco C# quindi non posso commentare su quella parte. Personalmente – e sono sicuro che molte persone potrebbero non shoot me down, io direi che in generale una procedura che dovrebbe fare una certa quantità di lavoro e può avere un impatto sia sui dati che è e non è passato (che non è necessariamente a conoscenza), e una funzione deve restituire un risultato basato sul passato di dati e, preferibilmente, non hanno effetti collaterali. Ma è tutto ciò che è più adatto per quello che stai facendo. Andando indietro e cambiare il vecchio codice è improbabile per aggiungere molto, avrei pensato.
  • Ho affrontato problemi simili. Quindi ho dovuto ricorrere cambiare le mie funzioni di stored procedure. Non ho risposta dal momento che questa domanda è vecchia. Modifica CommandType suggerimento dato da Slider345 non funziona se la funzione restituisce un REFCURSOR. Funziona se si dispone di una funzione scalare, che restituisce un valore e non un recordset. Anche In questo caso, è necessario utilizzare la funzione in una query del tipo “SELECT nome_funzione DA DOPPIO”. Forse si potrebbe provare con questo approccio la funzione di cui sopra. Cambia il tuo commandtype di TESTO e quindi modificare la sintassi per richiamare la funzione.
  • Hai visto il “Test il CURSORE di riferimento Procedura da C#” sezione questo link — metà strada verso il basso la pagina per me.
  • Pony. Che funziona alla grande per PROCEDUREs. Per FUNCTIONs non così tanto.
  • Per favore, sentitevi liberi di rispondere a domande vecchie, vedere blog. Purtroppo, quando ho provato il tuo approccio, che ha portato in uno strano errore di memoria.
  • Perchè devi essere così pignolo? :p
  • Credo di avere un fix per voi. Ho postato una domanda molto simile in Oracle Forum, dove qualcuno ha sottolineato il modo corretto di fare questo. Ha funzionato per me, quindi deve lavorare per è così. Controllare questo link. forums.oracle.com/forums/message.jspa?messageID=9369507#9369507
  • qualsiasi soluzione finale con il codice sorgente completo di esempio ?
  • che cosa ti senti mancanti dal blocco di seguito l ‘ “ultima Modifica” o risposta

InformationsquelleAutor Conrad Frix | 2010-08-20



4 Replies
  1. 5

    Non ho testato questo con una funzione, ma per la mia stored procedure. Specificare il parametro per la refCursor.

    command.Parameters.Add(new OracleParameter("refcur_questions", OracleDbType.RefCursor, ParameterDirection.Output));

    Se siete in grado di ottenere la funzione di lavorare con CommandType.Di testo. Mi chiedo se si può provare ad aggiungere il parametro di cui sopra, tranne che con la direzione, come:

    ParameterDirection.ReturnValue

    Sto usando Oracle.DataAccess versione 2.111.6.0

    • Cosa si aspetta il nome il nome del parametro di output di essere? Ho provato diverse alternative
    • Frix credo che si può assegnare qualsiasi nome che si desidera, specificando la direzione del parametro come valore di ritorno sarebbe mappare i risultati, non ho testato questa sicurezza. Anche io sono imbattuto in questo link ritorno ref_cursor dalla funzione. Usano il metodo ExecuteNonQuery di accesso e il cursore tramite il parametro. È questa l’alternativa che hai trovato?
    • che fatto. Godetevi la vostra rinascita badge
    • L’alternativa che ho trovato è stato quello di utilizzare le procedure direttamente e dimenticare la scrittura di funzioni wrapper. Vedere il fondo del questa domanda
    • Frix Yay ho due scudetti ora =). Grazie!
  2. 1

    Ho dovuto andare su e giù tra la domanda e risposte per capire il codice completo che funziona. Così sto dando il codice completo qui che ha lavorato per me per gli altri –

    var sql = @"BEGIN :refcursor1 := mypackage.myfunction(:param1) ; end;";
    using(OracleConnection con = new OracleConnection("<connection string>"))
    using(OracleCommand com = new OracleCommand())
    {
         com.Connection = con;
         con.Open();
         com.Parameters.Add(":refcursor1", OracleDbType.RefCursor, ParameterDirection.Output);
         com.Parameters.Add(":param1", "param");
         com.CommandText = sql;
         com.CommandType = CommandType.Text;
         com.ExecuteNonQuery();
         OracleRefCursor curr = (OracleRefCursor)com.Parameters[0].Value;
         using(OracleDataReader dr = curr.GetDataReader())
         {
             if(dr.Read())
             {
                 var value1 = dr.GetString(0);
                 var value2 = dr.GetString(1);
             }
         }
     }

    Speranza che aiuta.

  3. 0

    La mia ipotesi è che non è possibile chiamare una funzione con un Comando di oggetti di tipo ‘StoredProcedure’. Si può provare un oggetto di Comando di tipo “Testo” e exec funzione all’interno del Testo del Comando?

  4. 0

    So che questo è piuttosto un vecchio post, ma dato che mi ci è voluto così tanto tempo per capire tutte le peculiarità che hanno permesso di arrivare .NETTO di lottare “bello” con Oracle, ho pensato di mettere questo consigli là fuori per chiunque altro in questa situazione appiccicosa.

    Mi capita spesso di chiamare Oracle stored procedure che restituisce un REF_CURSOR nel nostro ambiente (.NET 3.5 contro Oracle 11g). Per una funzione, è possibile, infatti, il nome del parametro tutto quello che volete, ma poi è necessario impostare la System.Data.ParameterDirection = ParameterDirection.ReturnValue poi ExecuteNonQuery contro il OracleCommand oggetto. A quel punto il valore di tale parametro sarà la ref_cursor che la funzione di Oracle restituiti. Appena lanciato il valore come OracleDataReader e loop attraverso la OracleDataReader.

    Mi piacerebbe postare il codice completo, ma ho scritto il livello di accesso ai dati in VB.NET anni fa, e la maggior parte del codice del consumo, il livello di accesso ai dati (la nostra intranet aziendale) si trova in C#. Ho pensato di mischiare le lingue in una sola risposta sarebbe la più grande gaffe.

Lascia un commento