Skip to Main Content

ODP.NET

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Interested in getting your voice heard by members of the Developer Marketing team at Oracle? Check out this post for AppDev or this post for AI focus group information.

Default values of Oracle SP parameters not working with ODP.net in DAAB 5.0

872745Jul 1 2011 — edited Jul 5 2011
I'm trying to use Oracle.DataAccess.Client provider 11g with Microsoft Enterprise Library DAAB 5.0. I have done the necessary customization for Oracle data types & RefCursor. Now the problem I'm facing is Oracle.DataAccess.Client provider uses stored procedure parameter binding by position. This I've changed by overriding GetStoredProcCommand where I've set the BindByName property of the DBCommand by boxing it as OracleCommand to true [ ((OracleCommand)command).BindByName = true; ]. The parameter collection is populated using the OracleCommandBuilder.DeriveParameters((OracleCommand)discoveryCommand).

The problem I'm facing is when I try to fetch a dataset from the stored procedure nothing is returned. I've identified the problem to be the default values of the stored procedure parameters. The stored procedure is like this

CREATE OR REPLACE PROCEDURE MYPROC
(
p_param1 IN NUMBER DEFAULT 4,
p_param2 IN VARCHAR2 DEFAULT NULL,
p_param3 IN VARCHAR2 DEFAULT NULL,
p_param4 IN VARCHAR2 DEFAULT NULL,
p_ref_cursor OUT sys_refcursor
) AS
v_sys_error NUMBER := 0;
BEGIN
BEGIN
IF p_opmode = 4 THEN
BEGIN
BEGIN
OPEN p_ref_cursor FOR SELECT FLD1,FLD2,FLD3 FROM MYTABLE WHERE FLD2 = p_param2;
EXCEPTION
WHEN OTHERS THEN
v_sys_error := SQLCODE;
END;
IF v_sys_error <> 0 THEN
BEGIN
GOTO err_handler;
END;
END IF;
END;
ELSE
BEGIN
BEGIN
OPEN p_ref_cursor FOR SELECT FLD1,FLD2,FLD3 FROM MYTABLE WHERE FLD2 = p_param3 AND FLD5 = p_param4;
EXCEPTION
WHEN OTHERS THEN
v_sys_error := SQLCODE;
END;
IF v_sys_error <> 0 THEN
BEGIN
GOTO err_handler;
END;
END IF;
END;
END IF;
END;
<<cleanup>>
RETURN;
<<err_handler>>
v_errormsg := fetchMsg(v_sys_error);
raise_application_error (-20002, ':' || v_errormsg);
GOTO cleanup;
END;

When I'm calling this SP I'm not assigning any value of the parameter "p_param1" since it has a default value (skipping the parameter). In this scenario the dataset returned does not contain a datatable. If I assign the value to the parameter then it returns records. Is there something I'm missing or doing wrong.

Oracle.DataAccess.dll 2.112.2.0

.Net Framework 3.5 SP 1

Visual Studio 2008

Oracle Database 10g Enterprise Edition Release 10.2.0.1.0

Comments

gdarling - oracle
I know virtually nothing about DAAB, but this works fine for me using ODP directly.. can you break it?

Greg
/* 
 CREATE OR REPLACE PROCEDURE defPROC
(
p1 IN VARCHAR2 DEFAULT 'foo',
p2 IN VARCHAR2 DEFAULT 'bar',
p3 IN VARCHAR2 DEFAULT 'baz',
p4 out varchar2
) AS
begin
 p4 := 'p1='||p1||', p2='||p2||', p3='||p3;
 end;
 /
 */
using System;
using System.Data;
using Oracle.DataAccess.Client;

class testdefvals
{
    static void Main(string[] args)
    {
        using (OracleConnection con = new OracleConnection("data source=orcl;user id=scott;password=tiger"))
        {
            con.Open();
            using (OracleCommand cmd = new OracleCommand("defProc", con))
            {
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.BindByName = true;
                cmd.Parameters.Add("p2", "secondval");
                OracleParameter outval = new OracleParameter("p4", OracleDbType.Varchar2, 4000);
                outval.Direction=ParameterDirection.Output;
                cmd.Parameters.Add(outval);
                cmd.ExecuteNonQuery();
                Console.WriteLine(outval.Value.ToString());

            }
        }
    }
}
MY OUTPUT
=======
p1=foo, p2=secondval, p3=baz
Press any key to continue . . .
872745
Hi Greg

Thanks for the sample but what I'v done is

DbCommand command = GetStoredProcCommand("Myproc");

public virtual DbCommand GetStoredProcCommand(string storedProcedureName)
{
if (string.IsNullOrEmpty(storedProcedureName)) throw new ArgumentException(Resources.ExceptionNullOrEmptyString, "storedProcedureName");

return CreateCommandByCommandType(CommandType.StoredProcedure, storedProcedureName);
}

DbCommand CreateCommandByCommandType(CommandType commandType,
string commandText)
{
DbCommand command = dbProviderFactory.CreateCommand();
command.CommandType = commandType;
command.CommandText = commandText;

BindParametersByName(command, true);
return command;
}

public override void BindParametersByName(DbCommand command, bool bindingFlag)
{
((OracleCommand)command).BindByName = bindingFlag;
}

the parameter collection is populated using the OracleCommandBuilder.DeriveParameters((OracleCommand)command).

Now I'm just assigning the values to the parameters that I need and calling

DataSet ds = ExecuteDataSet(command);

public virtual DataSet ExecuteDataSet(DbCommand command)
{
DataSet dataSet = new DataSet();
dataSet.Locale = CultureInfo.InvariantCulture;
DoLoadDataSet(command, dataSet);
return dataSet;
}

void DoLoadDataSet(DbCommand command, DataSet dataSet)
{
using (OracleDataAdapter adapter = (OracleDataAdapter)GetDataAdapter(UpdateBehavior.Standard))
{
adapter.SelectCommand = (OracleCommand)command;
adapter.Fill(dataSet);
}
}

This works fine if I explicitly specify the value again to the parameters which have default values but fails if I skip the parameter with the default value.
gdarling - oracle
Hi,

I think what it boils down to is that DervieParameters is deriving parameters for all of the proc params, even though they have default values, and that seems to me to be the correct behavior. Once you have parameters in the collection, if you don't assign a value to them, null will be passed.

What you probably need to do is

1) the best option, is not to use deriveparameters in the first place, and manually build the parameters collection, adding parameters for only the things you don't want to have default values:

http://download.oracle.com/docs/cd/B28359_01/win.111/b28375/OracleCommandBuilderClass.htm#CHDGJBGD
<snip>
DeriveParameters incurs a database round-trip and should only be used during design time. To avoid unnecessary database round-trips in a production environment, the DeriveParameters method itself should be replaced with the explicit parameter settings that were returned by the DeriveParameters method at design time.
</snip>

2) If you want to continue using DeriveParameters, remove the unwanted parameters from the OracleParameters collection.

Hope it helps,
Greg

UPDATED SAMPLE
----------------------------
/* 

CREATE OR REPLACE PROCEDURE defPROC
 (
 p1 IN VARCHAR2 DEFAULT 'foo',
 p2 IN VARCHAR2 DEFAULT 'bar',
 p3 IN VARCHAR2 DEFAULT 'baz',
 p4 out varchar2
 ) AS
 begin
  p4 := 'p1='||nvl(p1,'p1null')||', p2='||nvl(p2,'p2null')||', p3='||nvl(p3,'p3null');
  end;
 */
using System;
using System.Data;
using Oracle.DataAccess.Client;

class testguid
{
    static void Main(string[] args)
    {
        using (OracleConnection con = new OracleConnection("data source=orcl;user id=scott;password=tiger"))
        {
            con.Open();
            using (OracleCommand cmd = new OracleCommand("defProc", con))
            {
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.BindByName = true;
                OracleCommandBuilder.DeriveParameters(cmd);
                cmd.Parameters[1].Value = "secondval";
                cmd.ExecuteNonQuery();
                Console.WriteLine(cmd.Parameters[3].Value.ToString());

            }
        }

        using (OracleConnection con = new OracleConnection("data source=orcl;user id=scott;password=tiger"))
        {
            con.Open();
            using (OracleCommand cmd = new OracleCommand("defProc", con))
            {
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.BindByName = true;
                OracleCommandBuilder.DeriveParameters(cmd);
                // remove the first param
                cmd.Parameters.RemoveAt(0);
                // the third param is now the second param, remove it too.
                cmd.Parameters.RemoveAt(1);
                // this is the second value of the proc, but the first param of the collection, jsut
                // as it was when we coded it manually
                cmd.Parameters[0].Value = "secondval";
                cmd.ExecuteNonQuery();
                // the 4th proc param is now the second in the collection
                Console.WriteLine(cmd.Parameters[1].Value.ToString());

            }
        }
    }
}
OUTPUT
==============
p1=p1null, p2=secondval, p3=p3null
p1=foo, p2=secondval, p3=baz
Press any key to continue . . .


Edited by: gdarling on Jul 5, 2011 12:03 PM

Edited by: gdarling on Jul 5, 2011 12:04 PM
1 - 3
Locked Post
New comments cannot be posted to this locked post.

Post Details

Locked on Aug 2 2011
Added on Jul 1 2011
3 comments
5,346 views