使用Null从C#调用Oracle函数

时间:2018-07-18 16:02:14

标签: c# oracle12c data-access-layer odp.net

我正在尝试从我们的C#应用​​程序调用Oracle函数,但是我遇到以下错误。我认为我有两个问题:

  1. 我想调用此函数,但是C#端的某些参数可以为null,因此我不知道如何处理它们。

  2. 我不知道是否需要在ParameterDirection.ReturnValue对象上使用OracleParameter将返回值添加到参数中。

这是我正在尝试的:

public int GetActivityRowCount(DateTime fromDate, DateTime thruDate, string grpCds, string catCds, string typCds, long? memNbr, long? subNbr, string searchBy, string dispActivity, string statCds, bool showUncategorized, string debugYN)
{
    OracleCommand cmd = null;

    try
    {
        StringBuilder sql = new StringBuilder();
        sql.Append(" pack_SomePack.func_SearchRowCount");


        cmd = new OracleCommand(sql.ToString(), this.Connection);
        cmd.CommandType = CommandType.StoredProcedure;

        // Don't know if I should add this guy
        // cmd.Parameters.Add(new OracleParameter("RowCount", OracleDbType.Int16, ParameterDirection.ReturnValue));

        cmd.Parameters.Add(new OracleParameter("FromDate", OracleDbType.Date, fromDate, ParameterDirection.Input));
        cmd.Parameters.Add(new OracleParameter("ThruDate", OracleDbType.Date, thruDate, ParameterDirection.Input));
        cmd.Parameters.Add(new OracleParameter("grpCds", OracleDbType.Varchar2, grpCds, ParameterDirection.Input));
        cmd.Parameters.Add(new OracleParameter("catCds", OracleDbType.Varchar2, catCds, ParameterDirection.Input));
        cmd.Parameters.Add(new OracleParameter("typCds", OracleDbType.Varchar2, typCds, ParameterDirection.Input));
        cmd.Parameters.Add(new OracleParameter("memNbr", OracleDbType.Long, memNbr, ParameterDirection.Input));
        cmd.Parameters.Add(new OracleParameter("SubNbr", OracleDbType.Long, SubNbr, ParameterDirection.Input));
        cmd.Parameters.Add(new OracleParameter("searchBy", OracleDbType.Varchar2, searchBy, ParameterDirection.Input));
        cmd.Parameters.Add(new OracleParameter("dispActivity", OracleDbType.Varchar2, dispActivity, ParameterDirection.Input));
        cmd.Parameters.Add(new OracleParameter("statCds", OracleDbType.Varchar2, statCds, ParameterDirection.Input));
        cmd.Parameters.Add(new OracleParameter("showUncategorized", OracleDbType.Char, showUncategorized? "Y" : "N", ParameterDirection.Input));
        cmd.Parameters.Add(new OracleParameter("debugYN", OracleDbType.Varchar2, debugYN, ParameterDirection.Input));

        cmd.BindByName = true;

        int activityRowCount = Convert.ToInt16(cmd.ExecuteScalar()); // Error here

        return activityRowCount;
    }

我的功能执行以下操作:

FUNCTION func_SearchRowCount
(
    in_FromDate         IN DATE,
    in_ThruDate         IN DATE,
    in_GrpCds           IN VARCHAR2,
    in_CatCds           IN VARCHAR2,
    in_TypCds           IN VARCHAR2,
    in_MemNbr           IN Actv.PersNbr%TYPE,
    in_SubNbr           IN Actv.SubNbr%TYPE,
    in_SearchBy         IN VARCHAR2,
    in_dispActivity     IN VARCHAR2,
    in_StatCds          IN Ams.StatCd%TYPE,
    in_UncategorizedYN  IN CHAR,
    in_DebugYN          IN CHAR
) RETURN NUMBER AS

    lvnCount            NUMBER;
    lvsSqlStr           VARCHAR2(2000);

BEGIN
    lvsSqlStr := 'SELECT COUNT(*) FROM SomeTable WHERE (Include a bunch of clauses..)';
    BEGIN
        EXECUTE IMMEDIATE lvsSqlStr
                INTO lvnCount
                USING (All the parameters);
    END;

    RETURN lvnCount;

END func_SearchRowCount;

运行上述内容时,出现以下错误。

PLS-00306: wrong number or types of arguments in call to 'FUNC_SEARCHROWCOUNT'

所有变量都绑定有正确的数量,尽管我读到某个地方ODP.NET将在null处使用.Value删除参数。这是真的?我应该传递什么来指示该参数没有值?

2 个答案:

答案 0 :(得分:1)

您至少需要四件事:

  

您以与存储过程相同的方式执行功能。使用ParameterDirection.ReturnValue参数获取该函数返回的结果。

  • 在第三方面,请使用DbNull.Value,因为它是为数据库中represent null values的占位符而专门设计的,而null仅对.NET有意义。 (嗯,null可能还可以,因为Oracle驱动程序可能足够聪明来处理它; DbNull.Value是一个好习惯,尽管因为您很明确)。您可以做类似的事情

new OracleParameter("typCds", OracleDbType.Varchar2, typCds ?? (object)DbNull.Value, ParameterDirection.Input));

  • 最后,您已经按名称绑定了参数,但名称与参数名称不匹配。完全匹配名称或按位置绑定。

对于特定错误,返回值是“参数”,并且未正确绑定参数。 Oracle需要13个参数,而您实际上没有给它。

答案 1 :(得分:1)

您的代码似乎有几个问题。 Oracle Type LONG与C#中的LONG不同,Oracle DB中的LONG允许您存储最大2GB的字符数据。在C#中,它是使用64位的数字类型。由于您提交的代码无法说明包函数中的参数in_MemNbr,in_SubNbr和in_StatCds是什么类型的数据,我只能猜测,这取决于您在c#方法中参数列表的定义。

您在C#中的“新OracleParameter(“”)”语句中的参数名称与函数参数不完全匹配。在Pl / Sql中,您添加了“ in_”前缀,但在c#代码中将其删除。使用“ cmd.BindByName = true;”您对ODP.Net说:“嘿,通过名称而不是使用位置绑定集合中的参数”。在这种情况下,它们必须完全匹配。

方法的C#返回值为int(System.Int32),PlSql包函数的返回值为NUMBER。如果数字没有指定的小数位数,ODP.Net似乎在C#中返回小数。当ODP.Net尝试在内部将oracle数字类型转换为short(Int16)时,您可能会遇到转换/无效广播异常。当返回的计数大于short.MaxValue时,可能会收到超出范围的异常。尝试在创建返回值参数时将Int32指定为返回值。

OracleCommand实现IDisposable接口。请确保不再使用命令,因为对象中IDisposable接口的实现会向您显示该对象会创建/使用某些资源(托管或非托管),并且必须在操作完成后释放它们。最快捷的方法是使用  C#的“ using”关键字,可确保在代码执行离开块时调用cmd.Dispose(),而不管是否发生异常或块成功结束。

    public int GetActivityRowCount(DateTime fromDate, DateTime thruDate, string grpCds, string catCds, string typCds, long? memNbr, long? subNbr, string searchBy, string dispActivity, string statCds, bool showUncategorized, string debugYN)
    {
        using (var cmd = new OracleCommand("pack_SomePack.func_SearchRowCount", this.Connection))
        using (var result = new OracleParameter("result", OracleDbType.Int32, ParameterDirection.ReturnValue))
        using (var fromDateParam = new OracleParameter("in_FromDate", OracleDbType.Date, fromDate, ParameterDirection.Input))
        using (var thruDateParam = new OracleParameter("in_ThruDate", OracleDbType.Date, thruDate, ParameterDirection.Input))
        using (var grpCdsParam = new OracleParameter("in_GrpCds", OracleDbType.Varchar2, grpCds, ParameterDirection.Input))
        using (var catCdsParam = new OracleParameter("in_CatCds", OracleDbType.Varchar2, catCds, ParameterDirection.Input))
        using (var typCdsParam = new OracleParameter("in_TypCds", OracleDbType.Varchar2, typCds, ParameterDirection.Input))
        using (var memNbrParam = new OracleParameter("in_MemNbr", OracleDbType.Int64, memNbr, ParameterDirection.Input))
        using (var subNbrParam = new OracleParameter("in_SubNbr", OracleDbType.Int64, SubNbr, ParameterDirection.Input))
        using (var searchByParam = new OracleParameter("in_SearchBy", OracleDbType.Varchar2, searchBy, ParameterDirection.Input))
        using (var dispActivityParam = new OracleParameter("in_dispActivity", OracleDbType.Varchar2, dispActivity, ParameterDirection.Input))
        using (var statCdsParam = new OracleParameter("in_StatCds", OracleDbType.Varchar2, statCds, ParameterDirection.Input))
        using (var uncategorizedYnParam = new OracleParameter("in_UncategorizedYN", OracleDbType.Char, showUncategorized ? "Y" : "N", ParameterDirection.Input))
        using (var debugYnParam = new OracleParameter("in_DebugYN", OracleDbType.Char, debugYN, ParameterDirection.Input))
        {
            cmd.CommandType = CommandType.StoredProcedure;

            cmd.Parameters.Add(result);
            cmd.Parameters.Add(fromDateParam);
            cmd.Parameters.Add(thruDateParam);
            cmd.Parameters.Add(grpCdsParam);
            cmd.Parameters.Add(catCdsParam);
            cmd.Parameters.Add(typCdsParam);
            cmd.Parameters.Add(memNbrParam);
            cmd.Parameters.Add(subNbrParam);
            cmd.Parameters.Add(searchByParam);
            cmd.Parameters.Add(dispActivityParam);
            cmd.Parameters.Add(statCdsParam);
            cmd.Parameters.Add(uncategorizedYnParam);
            cmd.Parameters.Add(debugYnParam);

            cmd.BindByName = true;

            cmd.ExecuteNonQuery();

            return Convert.ToInt32(result.Value);
        }
    }