2010-11-08 54 views
9

J'essaie d'exécuter une fonction Oracle définie par l'utilisateur qui renvoie un RefCursor en utilisant ODP.NET. Voici la fonction:Comment renvoyer une fonction RefCursor de Oracle?

CREATE OR REPLACE FUNCTION PKG.FUNC_TEST (ID IN TABLE.ID%type) 
    RETURN SYS_REFCURSOR 
AS 
    REF_TEST SYS_REFCURSOR; 
BEGIN 
    OPEN REF_TEST FOR 
     SELECT * 
     FROM TABLE; 
    RETURN REF_TEST; 
END; 
/

Je peux appeler cette fonction dans Toad (sélectionnez func_test (7) double) et retourner un curseur. Mais j'ai besoin d'obtenir le curseur en utilisant C# et ODP.NET pour remplir un DataSet, mais je reçois toujours une NullReferenceException - "Référence d'objet non définie à une instance d'un objet". Voici ce que je dois pour cela:

OracleConnection oracleCon = new OracleConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString); 
OracleCommand sqlCom = new OracleCommand("select func_test(7) from dual", oracleCon); 
sqlCom.Parameters.Add("REF_TEST", OracleDbType.RefCursor, ParameterDirection.ReturnValue); 
OracleDataAdapter dataAdapter = new OracleDataAdapter(); 
dataAdapter.SelectCommand = sqlCom; 

DataSet dataSet = new DataSet(); 
dataAdapter.Fill(dataSet); //FAILS HERE with NullReferenceException 

j'ai pu trouver beaucoup d'informations et d'échantillons sur l'utilisation des procédures stockées et ODP.NET, mais pas tant pour le retour RefCursors des fonctions.

EDIT: Je ne veux pas ajouter explicitement les paramètres d'entrée à l'objet OracleCommand (c.-à-sqlCom.Parameters.Add("id", OracleDbType.Int32,ParameterDirection.Input).Value = 7;) comme qui le rend difficile à mettre en œuvre cela comme un service Web RESTful générique, mais je réserver comme mon dernier recours mais utiliserait plutôt des procédures stockées.

Toute aide est très appréciée!

+0

Vous ajoutez un paramètre mais vous l'exécutez en tant que requête; ne voulez-vous pas faire quelque chose comme ': REF_TEST: = func_test (7)'? –

+0

Vous ne savez pas où l'utiliser. Est-ce utilisé à la place du paramètre? – Gady

+0

comme chaîne OracleCommand, au lieu de select. (Je devrais peut-être souligner que je ne sais rien sur ODP.Net, mais cela semble toujours faux * 8-) –

Répondre

15

Je pense qu'il vous manque le sqlCom.ExecuteNonQuery();

également, au lieu d'exécuter le sélectionnez func_test (7) à partir du dual; permet de passer à exécuter la fonction et de passer dans le param

OracleConnection oracleCon = new OracleConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString); 


    // Set the command 

    string anonymous_block = "begin " + 
           " :refcursor1 := func_test(7) ;" + 
           "end;"; 
//fill in your function and variables via the above example 
    OracleCommand sqlCom= con.CreateCommand(); 
    sqlCom.CommandText = anonymous_block; 

    // Bind 
    sqlCom.Parameters.Add("refcursor1", OracleDbType.RefCursor); 
    sqlCom.Parameters[0].Direction = ParameterDirection.ReturnValue; 

    try 
    { 
    // Execute command; Have the parameters populated 
    sqlCom.ExecuteNonQuery(); 

    // Create the OracleDataAdapter 
    OracleDataAdapter da = new OracleDataAdapter(sqlCom); 

    // Populate a DataSet with refcursor1. 
    DataSet ds = new DataSet(); 
    da.Fill(ds, "refcursor1", (OracleRefCursor)(sqlCom.Parameters["refcursor1"].Value)); 

    // Print out the field count the REF Cursor 
    Console.WriteLine("Field count: " + ds.Tables["refcursor1"].Columns.Count); 
    } 
    catch (Exception e) 
    { 
    Console.WriteLine("Error: {0}", e.Message); 
    } 
    finally 
    { 
    // Dispose OracleCommand object 
    cmd.Dispose(); 

    // Close and Dispose OracleConnection object 
    con.Close(); 
    con.Dispose();} 

ceci est basé sur l'exemple ODP qui peut être trouvé @% ORA_HOME% \ Client_1 \ ODP.NET \ samples \ refcursor \ Sample5.csproj

Si vous voulez éviter (pour le meilleur ou le pire!) La collection de paramètres personnalisés pour chaque appel proc/function, vous pouvez contourner cela en utilisant des blocs anonymes dans votre code, j'ai recommandé (encore une fois non testé!) Le code ci-dessus pour refléter cette technique. Voici un joli blog (de nul autre que Mark Williams) montrant cette technique. http://oradim.blogspot.com/2007/04/odpnet-tip-anonymous-plsql-and.html

+0

Cela pourrait fonctionner, mais comme cela sera utilisé dans un service Web RESTful, j'essaie d'éviter l'ajout explicite de paramètres d'entrée (ie 'sqlCom.Parameters.Add (" id ", OracleDbType. Int32, ParameterDirection.Input) .Value = 7; ') afin que je puisse facilement créer une instruction SQL à la volée. – Gady

+0

@Guddie, vous pouvez utiliser des blocs anonymes pour lui donner la sensation «générique» que vous recherchez. J'ai changé l'exemple ci-dessus pour refléter cela – Harrison

+0

OUI! Vous gagnez! Exactement ce que je cherchais! – Gady