Oracle存储过程包含来自托管数据访问的多个阵列和标量

时间:2018-06-18 13:05:27

标签: c# arrays oracle oracle-manageddataaccess

我正在尝试从Oracle托管数据访问客户端调用以下Oracle存储过程

PROCEDURE CLONE_PRODUCT(p_f_cloned_prod_id    IN      product.product_id%TYPE,
                        p_f_name              IN      product.name%TYPE,
                        p_f_desc              IN      product.presentation_value%TYPE,
                        p_f_sys_issue         IN      product.product_reference%TYPE,
                        p_f_feature_names     IN      T_CHAR_TAB,
                        p_f_feature_values    IN      T_CHAR_TAB,
                        p_f_audit_user        IN      product.last_updated_by%TYPE,
                        p_f_product_id           OUT  product.product_id%TYPE)

其中

TYPE  t_char_tab  IS TABLE OF VARCHAR2(1000) INDEX BY BINARY_INTEGER;

使用此C#代码:

 using (var cloneProductCmd = new OracleCommand("SPF_SQL.CLONE_PRODUCT", con))
 {
     cloneProductCmd.BindByName = true;
     cloneProductCmd.CommandType = System.Data.CommandType.StoredProcedure;

     cloneProductCmd.Parameters.Add("P_F_CLONED_PROD_ID", 1);
     cloneProductCmd.Parameters.Add("P_F_NAME", "bob");
     cloneProductCmd.Parameters.Add("P_F_DESC", "bob smith");
     cloneProductCmd.Parameters.Add("P_F_SYS_ISSUE", 123);

     var featureNames = new OracleParameter()
     {
         ParameterName = "P_F_FEATURE_NAMES",
         Direction = System.Data.ParameterDirection.Input,
         OracleDbType = OracleDbType.Varchar2,
         Value = new string[] { "feature 1" }
     };
     cloneProductCmd.Parameters.Add(featureNames);

     var featureValues = new OracleParameter()
     {
         ParameterName = "P_F_FEATURE_VALUES",
         Direction = System.Data.ParameterDirection.Input,
         OracleDbType = OracleDbType.Varchar2,
         Value = new string[] { "value 1" }
     };
     cloneProductCmd.Parameters.Add(featureValues);
     cloneProductCmd.Parameters.Add("P_F_AUDIT_USER", "me");
     cloneProductCmd.Parameters.Add("P_F_PRODUCT_ID", OracleDbType.Decimal, System.Data.ParameterDirection.Output);

     cloneProductCmd.ArrayBindCount = 1;

     var reader = await cloneProductCmd.ExecuteNonQueryAsync();

     newProductId = Convert.ToInt32(cloneProductCmd.Parameters["P_F_PRODUCT_ID"].Value.ToString());
}

我尝试将ArraybindCount更改为2(2个长度为1的数组),并尝试指定数组参数的collectionTypePLSQLAssociativeArray

我总是收到一条消息:

  

无法转换类型为#System; Int32'的对象输入' System.Array'

this回答和this文章表明,ArrayBindCount属性意味着客户端期望所有参数都有一个数组。

我的问题是如何调用存储过程传递多个标量值和多个数组(所有数组具有相同数量的元素)以及out参数(标量)?

1 个答案:

答案 0 :(得分:0)

我最终解决了这个问题,在this答案的帮助下,我调整了我的代码并让它发挥作用。

简而言之,ArrayBindCount似乎是不必要的,但是对于每个数组参数CollectionType, Size, ArrayBindSize and ArrayBindStatus都是必需的,我还通过直接添加到命令的Parameter集合来创建参数而不是单独创建它们然后将它们添加到集合中,不确定它是否相关。

这是我的工作代码:

using (var cloneProductCmd = new OracleCommand("SPF_SQL.CLONE_PRODUCT", con))
{
    cloneProductCmd.BindByName = true;
    cloneProductCmd.CommandType = System.Data.CommandType.StoredProcedure;
    cloneProductCmd.Parameters.Add("P_F_CLONED_PROD_ID", product.OriginalProductId);
    cloneProductCmd.Parameters.Add("P_F_NAME", productName);
    cloneProductCmd.Parameters.Add("P_F_DESC", fullProduct.ProductName);
    cloneProductCmd.Parameters.Add("P_F_SYS_ISSUE", fullProduct.SystemIssueNumber);

    var featureNames = cloneProductCmd.Parameters.Add("P_F_FEATURE_NAMES", OracleDbType.Varchar2);
    featureNames.Direction = System.Data.ParameterDirection.Input;
    featureNames.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
    featureNames.Value = features.Select(_ => _.Key).ToArray();
    featureNames.Size = features.Count();
    featureNames.ArrayBindSize = features.Select(_ => _.Key.Length).ToArray();
    featureNames.ArrayBindStatus = Enumerable.Repeat(OracleParameterStatus.Success, features.Count()).ToArray();

    var featureValues = cloneProductCmd.Parameters.Add("P_F_FEATURE_VALUES", OracleDbType.Varchar2);
    featureValues.Direction = System.Data.ParameterDirection.Input;
    featureValues.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
    featureValues.Value = features.Select(_ => _.Value).ToArray();
    featureValues.Size = features.Count();
    featureValues.ArrayBindSize = features.Select(_ => _.Value.Length).ToArray();
    featureValues.ArrayBindStatus = Enumerable.Repeat(OracleParameterStatus.Success, features.Count()).ToArray();

    cloneProductCmd.Parameters.Add("P_F_AUDIT_USER", HttpContext.Current.User.Identity.Name);
    cloneProductCmd.Parameters.Add("P_F_PRODUCT_ID", OracleDbType.Decimal, System.Data.ParameterDirection.Output);

    var reader = await cloneProductCmd.ExecuteNonQueryAsync();

    newProductId = Convert.ToInt32(cloneProductCmd.Parameters["P_F_PRODUCT_ID"].Value.ToString());
}