0

我正在尝试从 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 的数组),并尝试指定数组参数collectionType具有PLSQLAssociativeArray.

我总是收到一条异常消息:

无法将“System.Int32”类型的对象转换为“System.Array”类型

这个答案和这篇文章表明该ArrayBindCount属性意味着客户端期望所有参数的数组。

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

4

1 回答 1

0

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

简而言之,这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());
}
于 2018-06-19T08:46:00.637 回答