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
当我从 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