我正在尝试从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'
this回答和this文章表明,ArrayBindCount
属性意味着客户端期望所有参数都有一个数组。
我的问题是如何调用存储过程传递多个标量值和多个数组(所有数组具有相同数量的元素)以及out参数(标量)?
答案 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());
}