如何修复无法使用 Oracle PL/SQL 存储过程在 C# ADO.NET 中将类型为“System.string”的对象转换为类型为“System.Array”的问题

问题描述 投票:0回答:1

每当我到达尝试插入数组的端点时,我都会遇到上述错误。我创建了一个自定义类型并将其添加到我的过程中。我在表中添加了一列,并使其键入我创建的自定义类型。自定义类型是

metric_array `` vararay(10) varchar2(255)
。我已经为此奋斗了一整天了。

这就是我到目前为止所做的。这是我的 C# 代码片段

cmd.Parameters.Add("p_account_no", newConcession.AccountNumber);
                    cmd.Parameters.Add("p_customer_no", newConcession.CustomerNumber);
                    cmd.Parameters.Add("p_customer_name", newConcession.CustomerName);
                    cmd.Parameters.Add("p_old_rate", newConcession.OldRate);
                    cmd.Parameters.Add("p_proposed_rate", newConcession.ProposedRate);
                    cmd.Parameters.Add("p_product", newConcession.Product);
                    cmd.Parameters.Add("p_product_type", newConcession.ProductType);
                    cmd.Parameters.Add("p_concession_type", newConcession.ConcessionType);
                    cmd.Parameters.Add("p_old_fee", newConcession.OldFee);
                    cmd.Parameters.Add("p_proposed_fee", newConcession.ProposedFee);
                    cmd.Parameters.Add("p_justification", newConcession.Justification);
                    cmd.Parameters.Add("p_commitment", newConcession.Commitment);
                    cmd.Parameters.Add("p_liability_impact", newConcession.LiabilityImpact);
                    cmd.Parameters.Add("p_revenue_impact", newConcession.RevenueImpact);
                    cmd.Parameters.Add("p_concession_details", newConcession.ConcessionDetails);
                    cmd.Parameters.Add("p_approval_stage", newConcession.ApprovalStage);
                    cmd.Parameters.Add("p_line_manager", LineManagerName);
                    cmd.Parameters.Add("p_bulk_upload_id", newConcession.BulkUploadId);
                    cmd.Parameters.Add("p_maker_id", StaffId);
                    //cmd.Parameters.Add("p_maker_date_time", newConcession.MakerDateTime);
                    cmd.Parameters.Add("p_modifier_id", newConcession.ModifierId);
                    cmd.Parameters.Add("p_modified_date_time", newConcession.ModifiedDateTime);
                    //cmd.Parameters.Add("p_record_stat", newConcession.RecordStat);
                    cmd.Parameters.Add("p_concession_creation_type",                  newConcession.ConcessionCreationType);
                    cmd.Parameters.Add("p_covenant_start_date", newConcession.CovenantStartDate);
                    cmd.Parameters.Add("p_covenant_end_date", newConcession.CovenantEndDate);
                    cmd.Parameters.Add("p_covenant_amount", newConcession.CovenantAmount);
                    cmd.Parameters.Add("p_reference_number", newConcession.ReferenceNumber);
                    cmd.Parameters.Add("p_created_at", createdAt);
                    cmd.Parameters.Add("p_updated_at", createdAt);
                    cmd.Parameters.Add("p_document_path", "koshi danu");
                    cmd.Parameters.Add("p_line_manager_number", newConcession.LineManagerNumber);
                    cmd.Parameters.Add("p_branch_name", newConcession.BranchName);
                    cmd.Parameters.Add("p_region", newConcession.Region);
                    cmd.Parameters.Add("p_business_segment", newConcession.BusinessSegment);
                    cmd.Parameters.Add("p_operational_region", newConcession.OperationalRegion);
                    cmd.Parameters.Add("p_actual", newConcession.Actual);
                    cmd.Parameters.Add("p_area", newConcession.Area);
                    cmd.Parameters.Add("p_approval_date", newConcession.ApprovalDate);
                    cmd.Parameters.Add("p_review_date", newConcession.ReviewDate);
                    cmd.Parameters.Add("p_category", newConcession.Category);

                    Console.WriteLine("This is the valueeeeeee of concession metrics" + newConcession.ConcessionMetrics.ToString());
                    //var metricArray = newConcession.ConcessionMetrics.ToArray() ?? Array.Empty<string>();
                    //var metricArray = newConcession.ConcessionMetrics.ToArray();

                    //List<string> metricArray = newConcession.ConcessionMetrics;
                    if (newConcession != null && newConcession.ConcessionMetrics != null)
                    {
                        Console.WriteLine("Concession Metrics:");
                        foreach (var metric in newConcession.ConcessionMetrics)
                        {
                            Console.WriteLine(metric);
                        }
                    }
                    else
                    {
                        Console.WriteLine("ConcessionMetrics is null or empty");
                    }

                    List<string> metricList = newConcession.ConcessionMetrics ?? new List<string>();
                    string[] metricArray = metricList.ToArray();

                    //string metricString = string.Join(",", metricArray);
                    OracleParameter arrayParam = new OracleParameter
                    {
                        ParameterName = "p_metric_array",
                        OracleDbType = OracleDbType.Array,
                        UdtTypeName = "METRIC_ARRAY_TYPE",
                        CollectionType = OracleCollectionType.None,
                        Direction = ParameterDirection.Input,
                        Size = metricArray.Length,
                        Value = metricArray.ToArray()
                };


       
                    cmd.Parameters.Add(arrayParam);
                    cmd.ArrayBindCount = metricArray.Length;

                    cmd.BindByName = true;
                    await connection.OpenAsync();
                    
                    OracleParameter concessionIdParam = new OracleParameter
                    {
                        ParameterName = "p_concession_id",
                        OracleDbType = OracleDbType.Decimal,
                        Direction = ParameterDirection.Output
                    };
                 
                    cmd.Parameters.Add(concessionIdParam);

                    await cmd.ExecuteNonQueryAsync();
                    
                    OracleDecimal concessionIdDecimal = (OracleDecimal)cmd.Parameters["p_concession_id"].Value;
                    decimal decimalValue = concessionIdDecimal.Value;
                    int concessionId = Convert.ToInt32(decimalValue);
                    Console.WriteLine("this is concessionid type " + concessionId.GetType().ToString());

这就是 concessionMetrics 的样子

public List<string> ConcessionMetrics { get; set; }

这也是我的程序。部分零件

 p_metric_array metric_array_type
    returning concession_id into p_concession_id;
    
    update new_concession_tbl
    set metric_array = p_metric_array
    where concession_id = p_concession_id;
    commit;

这是我遇到的错误的完整堆栈跟踪

System.InvalidCastException: Unable to cast object of type 'System.String' to type 'System.Array'.
   at Oracle.ManagedDataAccess.Client.OracleParameter.SetNullIndicators()
   at Oracle.ManagedDataAccess.Client.OracleParameter.PreBind(OracleConnectionImpl connImpl, ColumnDescribeInfo cachedParamMetadata, Boolean& bMetadataModified, Int32 arrayBindCount, ColumnDescribeInfo& paramMetaData, Object& paramValue, Boolean isEFSelectStatement, SqlStatementType stmtType)
   at OracleInternal.ServiceObjects.OracleCommandImpl.InitializeParamInfo(ICollection paramColl, OracleConnectionImpl connectionImpl, ColumnDescribeInfo[] cachedParamMetadata, Boolean& bMetadataModified, Boolean isEFSelectStatement, MarshalBindParameterValueHelper& marshalBindValuesHelper)
   at OracleInternal.ServiceObjects.OracleCommandImpl.ProcessParameters(OracleParameterCollection paramColl, OracleConnectionImpl connectionImpl, ColumnDescribeInfo[] cachedParamMetadata, Boolean& bBindMetadataModified, Boolean isEFSelectStatement, MarshalBindParameterValueHelper& marshalBindValuesHelper)
   at OracleInternal.ServiceObjects.OracleCommandImpl.ExecuteNonQuery(String commandText, OracleParameterCollection paramColl, CommandType commandType, OracleConnectionImpl connectionImpl, Int32 longFetchSize, Int64 clientInitialLOBFS, OracleDependencyImpl orclDependencyImpl, Int64[]& scnFromExecution, OracleParameterCollection& bindByPositionParamColl, Boolean& bBindParamPresent, OracleException& exceptionForArrayBindDML, OracleConnection connection, Boolean isFromEF)
   at Oracle.ManagedDataAccess.Client.OracleCommand.ExecuteNonQuery()
   at System.Data.Common.DbCommand.ExecuteNonQueryAsync(CancellationToken cancellationToken)
   --- End of stack trace from previous location ---
   at Alero.DataSource.ConcessionRepoImpl.AddNewConcession(NewConcession newConcession, List`1 documentTitles, List`1 documentDescriptions, List`1 documents, String userId) in C:\\Users\\oilesanmi\\Documents\\Repositories\\Alero-Api\\Alero.DataSource\\ConcessionRepoImpl.cs:line 168
c# oracle plsql ado.net
1个回答
0
投票

首先我想说你使用

ArrayBindCount
的方式不正确。命令的这个选项意味着all参数是一个特定长度的数组。例如,这对于批量插入非常方便。

其次,使用 UDT 并不是将集合传递到数据库的最简单方法。如果您想将 UDT 从 .net 传递到预言机,则必须遵守所有强加的要求。它不能是一个简单的数组,.net类型应该实现IOracleCustomType和INullable接口。您可以在此链接查看完整示例。

将数组传递给 pl/sql 的最简单方法是使用 pl/sql 关联数组(...索引为...的表,您可以使用函数/过程在包头中定义):

const string sql =
    @"declare
        type t_arr is table of varchar2(255) index by pls_integer;
        l_val t_arr;
        l_concat varchar2(4000);
     begin
         l_val := :p_metric_array;
         if l_val.count = 0 then
             RAISE_APPLICATION_ERROR(-20000, 'Array is empty!');
         end if;
         l_concat := null;
         FOR i IN l_val.FIRST .. l_val.LAST
         LOOP
            l_concat := l_concat || l_val(i);
         END LOOP;
         :p_result := l_concat;
     end;";

string[] metricArray = { "asd", "qwe", "1", "2" };

using (OracleConnection con = new OracleConnection(conString))
{
    con.Open();

    using (OracleCommand cmd = con.CreateCommand())
    {
        OracleParameter arrayParam = new OracleParameter
        {
            ParameterName = "p_metric_array",
            OracleDbType = OracleDbType.Varchar2, // <<<
            CollectionType = OracleCollectionType.PLSQLAssociativeArray, // <<<
            Direction = ParameterDirection.Input,
            Size = metricArray.Length,
            Value = metricArray
        };
        cmd.Parameters.Add(arrayParam);

        OracleParameter outParameter = new OracleParameter
        {
            ParameterName = "p_result",
            OracleDbType = OracleDbType.Varchar2,
            Direction = ParameterDirection.Output,
            Size = 4000
        };
        cmd.Parameters.Add(outParameter);

        cmd.CommandText = sql;
        cmd.ExecuteNonQuery();

        Debug.WriteLine(outParameter.Value);
    }
}

您可以检查外部样本

© www.soinside.com 2019 - 2024. All rights reserved.