Oracle 函数调用的返回值返回 null

Posted

技术标签:

【中文标题】Oracle 函数调用的返回值返回 null【英文标题】:Return value from Oracle function call returns null 【发布时间】:2018-07-18 20:25:56 【问题描述】:

我正在尝试从我们的 C# 应用程序调用 Oracle 函数,但它返回 null 而不是数字。

该函数只执行 COUNT(*)RETURNS 只是那个数字。现在,当我尝试从 C# 端调用它时,我总是得到nullcmd.Parameters["RowCount"].Value。它不仅仅是null,而且看起来像一个以null 为值的空对象。

这是从 C# 端看的样子。

OracleCommand cmd = null;

try

    cmd = new OracleCommand("pack_Ams_ActivityChange.func_ActivitySearchRowCount", this.Connection);
    cmd.CommandType = CommandType.StoredProcedure;

    cmd.Parameters.Add(new OracleParameter("RowCount", OracleDbType.Decimal, ParameterDirection.ReturnValue));
    cmd.Parameters.Add(new OracleParameter("FromDate", OracleDbType.Date, DateTime.Now(), ParameterDirection.Input));
    cmd.Parameters.Add(new OracleParameter("ThruDate", OracleDbType.Date, DateTime.Now().AddDays(1), ParameterDirection.Input));

    int activityRowCount = 0;
    cmd.ExecuteNonQuery();

    // Errors here since .Value is null
    activityRowCount = ((OracleDecimal)cmd.Parameters["RowCount"].Value).ToInt32();

    return activityRowCount;

这是函数在数据库中的样子。

FUNCTION func_RowCount
(
 in_FromDate         IN DATE,
 in_ThruDate         IN DATE
) RETURN NUMBER AS
 lvnCount            NUMBER;
 lvsSqlStr           VARCHAR2(2000);
BEGIN

    lvsSqlStr := 'SELECT COUNT(*) FROM SomeTable WHERE StartDate > :in_FromDate AND StartDate < :in_ThruDate';

    EXECUTE IMMEDIATE lvsSqlStr INTO lvnCount USING in_FromDate, in_ThruDate;

    RETURN lvnCount;
END func_RowCount;

【问题讨论】:

这里的问题出在 C# 端。 oracle 中的 count(*) 至少返回数字 0,并且始终返回数字 >= 0。代码可能只是截取 0 并将其解释为 null,这可能取决于 ODP,但我是很确定就是这样。您可以尝试将其与System.DBNull 进行比较,我敢打赌它们永远不会相等,除非有东西将零作为返回码截获并使其成为null @g00dy 是的,将其与null 甚至DBNull.Value 进行比较得到false 现在我们知道它与NULL 不同,我们需要弄清楚是否只有0 值被转换为null。为此,只需将 pl/sql 函数设为return 1,然后将其设为return -1。完成此操作后返回此处并粘贴结果。 【参考方案1】:

我发现 Oracle 数字格式和 .NET 类型转换的奇怪结果和行为 - 特别是在使用没有任何精度的 NUMBER 格式时。我通常将值转换为 OracleDecimal 并使用它构建的 .IsNull 函数,而不是尝试使用 .NET DbNull.Value 等。

var temporaryResult = new OracleDecimal(cmd.Parameters["RowCount"].Value);
activityRowCount = temporaryResult.IsNull ? 0 : Convert.ToInt32(temporaryResult.Value);

仍然不确定为什么它返回 null!

【讨论】:

想想这个,你有没有试过通过元素[0]而不是名字来访问参数集合?【参考方案2】:

你只需要:

FUNCTION func_RowCount
(
 in_FromDate         IN DATE,
 in_ThruDate         IN DATE
) RETURN NUMBER AS
 lvnCount            NUMBER;
BEGIN
    SELECT COUNT(*) 
     INTO lvnCount 
     FROM SomeTable 
     WHERE StartDate > in_FromDate 
     AND StartDate < in_ThruDate;
    RETURN lvnCount;
EXCEPTION
 WHEN NO_DATA_FOUND THEN
  RETURN 0;
END func_RowCount;

有了这样的例外,即使您的 SELECT 以某种方式返回 null,您也将获得保证数量。完全不需要 EXECUTE 和绑定变量。

此外,由于这是一个函数,您可以将其结果作为通常的选择返回,无需像存储过程那样调用它。 像这样的东西可以解决问题:

cmd = new OracleCommand("select pack_Ams_ActivityChange.func_ActivitySearchRowCount(?,?) from dual", this.Connection);

【讨论】:

计数是否需要 no_data_found 异常? count(*) 即使你的表是空的也会返回 0 你是对的,在这个例子中它不是强制性的。这只是一个好习惯。

以上是关于Oracle 函数调用的返回值返回 null的主要内容,如果未能解决你的问题,请参考以下文章

请教:C# WebService调用Java WebService(返回Json类型数据) ,为啥接收为null

CXF编写的客户端调用XFire编写的服务端,返回值为null,没有报错

蓝桥ROS机器人之C++基础2总结和测评

Mybatis调用Oracle中的函数有返回值

在oracle数据库中nvl()是啥函数?

Oracle中nul()函数