来自托管数据访问的具有多个数组和标量的 Oracle 存储过程
Posted
技术标签:
【中文标题】来自托管数据访问的具有多个数组和标量的 Oracle 存储过程【英文标题】:Oracle stored procedure with multiple arrays and scalars from managed data access 【发布时间】:2018-06-18 13:05:27 【问题描述】:我正在尝试从 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 answer 和 this 文章建议 ArrayBindCount
属性意味着客户端期望所有参数的数组。
我的问题是如何调用一个存储过程,传入多个标量值和多个数组(所有数组都具有相同数量的元素)以及一个输出参数(标量)?
【问题讨论】:
【参考方案1】:我最终解决了这个问题,在 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());
【讨论】:
以上是关于来自托管数据访问的具有多个数组和标量的 Oracle 存储过程的主要内容,如果未能解决你的问题,请参考以下文章