2010-11-08 115 views
9

Estoy tratando de ejecutar una función de Oracle definida por el usuario que devuelve un RefCursor usando ODP.NET. Aquí está la función:¿Cómo devolver un RefCursor desde la función 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; 
/

puedo llamar a esta función en sapo (seleccione func_test (7) de la doble) y volver a un cursor. Pero necesito obtener el cursor usando C# y ODP.NET para llenar un DataSet, pero sigo obteniendo una NullReferenceException - "Referencia de objeto no configurada para una instancia de un objeto". Aquí es lo que tengo para ello:

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 

yo era capaz de encontrar un montón de información y muestras sobre el uso de procedimientos almacenados y ODP.NET, pero no tanto para el retorno de RefCursors de funciones.

EDIT: no quiero añadir explícitamente los parámetros de entrada al objeto OracleCommand (es decir sqlCom.Parameters.Add("id", OracleDbType.Int32,ParameterDirection.Input).Value = 7;) como que hace que sea difícil implementar esto como un servicio web REST genérica, pero estoy reservando como mi último recurso pero usaría procedimientos almacenados en su lugar.

¡Cualquier ayuda es muy apreciada!

+0

Está agregando un parámetro pero lo está ejecutando como una consulta; ¿No quieres hacer algo como ': REF_TEST: = func_test (7)'? –

+0

No estoy seguro de dónde usar esto. ¿Se usa esto en lugar del parámetro? – Gady

+0

como la cadena OracleCommand, en lugar de la selección. (Tal vez debería señalar que no sé nada de ODP.Net, pero todavía se ve mal * 8-) –

Respuesta

15

Creo que se está perdiendo el sqlCom.ExecuteNonQuery();

también, en lugar de ejecutar seleccionar func_test (7) de dual; permite cambiar para que se ejecute la función y pase el parámetro

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();} 

esto se basa en el ejemplo PAO que se puede encontrar @% ora_home% \ Client_1 \ ODP.NET \ samples \ refcursor \ Sample5.csproj

Si desea evitar (¡para bien o para mal!) La colección personalizada de param para cada llamada de proceso/función puede evitar eso utilizando bloques anónimos en su código, he modificado (una vez más, no probado) el código arriba para reflejar esta técnica. Aquí hay un buen blog (de nada menos que Mark Williams) que muestra esta técnica. http://oradim.blogspot.com/2007/04/odpnet-tip-anonymous-plsql-and.html

+0

Esto podría funcionar, pero como esto se usará en un servicio web RESTful, estoy tratando de evitar la adición explícita de parámetros de entrada (es decir, 'sqlCom.Parameters.Add (" id ", OracleDbType). Int32, ParameterDirection.Input) .Value = 7; 'así que puedo construir fácilmente una declaración SQL sobre la marcha. – Gady

+0

@Guddie, puedes usar bloques anónimos para darle la sensación 'genérica' que estás buscando. He cambiado el ejemplo anterior para reflejar esto – Harrison

+0

¡SÍ! ¡Tú ganas! ¡Exactamente lo que estaba buscando! – Gady

Cuestiones relacionadas