ODP.NET OracleCommand 可选参数从不获取默认值

ODP.NET OracleCommand optional parameter never getting default value

当我从 PL/SQL 包调用函数时,有一个 IN 可选参数 (Date),默认值为 SYSDATE。

当我执行命令时,我别无选择,只能添加参数。即使没有设置值,该函数始终接收 null 作为输入值,因此它永远不会影响默认值。

            Dim cmd As New OracleCommand(con)
            cmd.CommandType = CommandType.StoredProcedure
            cmd.CommandText = "PACK.RefreshData"

            Dim param1 As New OracleParameter()
            param1.Direction = ParameterDirection.Input
            param1.ParameterName = "p_date"
            param1.DbType = DbType.Date
            cmd.Parameters.Add(param1)

            param1 = New OracleParameter()
            param1.Direction = ParameterDirection.Output
            param1.ParameterName = "po_errorCode"
            param1.DbType = DbType.String
            cmd.Parameters.Add(param1)

            param1 = New OracleParameter()
            param1.Direction = ParameterDirection.Output
            param1.ParameterName = "po_errorDescription"
            param1.DbType = DbType.String
            cmd.Parameters.Add(param1)

            con.Open()
            cmd.ExecuteNonQuery()

在另一个问题中,有人说命令 属性 BindByName 设置为 true 仅适用于常规查询,不适用于 storedProcs。那么,如果不使用我的 IN 参数传递值,我该如何调用该函数呢?

这是存储过程header

Procedure RefreshData
(
  p_date IN DATE := SYSDATE, 
  po_errorCode OUT  varchar2, 
  po_errorDescription OUT   varchar2
);

N.B。 : 我正在使用 Oracle.DataAccess.dll 版本 4.112.4.0

更新:这是从 oracle 线程中获取的解释,来自我在下面的回答:

我认为归根结底是 DervieParameters 正在为所有 proc 参数派生参数,即使它们具有默认值,在我看来这是正确的行为。一旦你在 collection 中有了参数,如果你不给它们赋值,就会传递 null。

您可能需要做的是

1) 最好的选择,首先是不要使用 deriveparameters,并手动构建参数 collection,只为您不想使用默认值的东西添加参数:

DeriveParameters 产生一个数据库 round-trip 并且应该只在设计时使用。为避免在生产环境中出现不必要的数据库 round-trip,应将 DeriveParameters 方法本身替换为 DeriveParameters 方法在设计时返回的显式参数设置。

2) 如果您想继续使用 DeriveParameters,请从 OracleParameters collection.

中删除不需要的参数

如果您的默认值参数不在参数链的尾部,您应该执行命名参数调用以避免传递此默认值参数。我认为您的数据提供者不支持这种调用类型,因此您应该将调用包装在匿名 pl\sql 块中,如下所示:

begin
    PACK.RefreshData(po_errorCode => :po_errorCode, po_errorDescription=>:po_errorDescription);
end;

然后执行之前在 VB 代码中执行的操作(当然你 CommandType 将是 Text)。

另一个解决方案是将默认值参数移动到参数链的末尾,如下所示:

Procedure RefreshData
(
  po_errorCode OUT  varchar2, 
  po_errorDescription OUT   varchar2,
  p_date IN DATE := SYSDATE 
);

我终于找到了一种方法来调用这个线程的过程:

https://community.oracle.com/thread/2248928?tstart=0

这是我更正的代码:

            con.Open()
            cmd = con.CreateCommand()
            cmd.CommandType = CommandType.StoredProcedure
            cmd.CommandText = "Pack.RefreshData"
            cmd.BindByName = True

            OracleCommandBuilder.DeriveParameters(cmd)
            cmd.Parameters.RemoveAt(0) 'I remove the optional parameter 

            cmd.ExecuteNonQuery()

然后我取回我的 OUT 参数

            Dim outPrm1 as String = ""
            If cmd.Parameters("po_errorDescription").Value IsNot Nothing Then
                outPrm1 = cmd.Parameters("po_errorDescription").Value
            End If