为什么RETURNING INTO子句会返回错误?

时间:2015-04-15 20:12:35

标签: c# oracle

我正在尝试插入Oracle数据库表并返回新创建的主键(通过触发器和序列)。

我有一段可行的代码。我有第二段代码在ExecuteNonQuery()上返回错误。

我不能为我的生活确定为什么第一个代码有效,第二个代码没有。

第一个工作代码:

        string sqlStr = @"INSERT INTO LEI_EROUTER_SESSIONS(empCID, JOBNUMBER, EMP_NAME, LOGGEDON, MACHINENAME, IP) values(:empCID, :JOBNUMBER, :EMP_NAME, sysdate, :MACHINENAME, :IP) RETURNING C_ID INTO :LASTCID";

        int C_ID;

        using (RetryClass RetryClassInstance = new RetryClass(CallingForm, JobSessionData, UserData))
        {
            do
            {
                RetryClassInstance.Retry = false;
                C_ID = 0;
                OracleConnection conn = new OracleConnection(Machine_Data.oracle_connstr);
                OracleCommand cmd = new OracleCommand(sqlStr, conn);
                try
                {
                    conn.Open();
                    cmd.Parameters.Add("empCID", UserData.employee_cid);
                    cmd.Parameters.Add("JOBNUMBER", JobSessionData.jobnumber);
                    cmd.Parameters.Add("EMP_NAME", UserData.employee_name);
                    //cmd.Parameters.Add("LOGGEDON", DateTime.Now);
                    cmd.Parameters.Add("MACHINENAME", Environment.MachineName);
                    cmd.Parameters.Add("IP", GlobalFunctions.LocalIPAddress());
                    cmd.Parameters.Add("LASTCID", OracleDbType.Int32, ParameterDirection.Output);
                    cmd.ExecuteNonQuery();

                    C_ID = Convert.ToInt32(cmd.Parameters["LASTCID"].Value.ToString());
                }
                catch (Exception ex)
                {
                    RetryClassInstance.HadException(ex);
                }
                finally
                {
                    if (cmd != null) cmd.Dispose();
                    if (conn != null) conn.Dispose();
                }
            } while (RetryClassInstance.Retry == true);
        }

        return C_ID;

以下是第二段不起作用的代码:

        string C_ID;
        List<string> C_IDS = new List<string>();

        string sqlStr = @"INSERT INTO LEI_CHECKIN_QUEUE(CHECKIN_DATE, JOB_ID, CELL, SN, STEP_NAME, STEP_TYPE, START_SEQ,
                          END_SEQ, CHECKEDINBY_EMP_CID, IN_QUEUE, PRIORITY_CODE, STEP_STARTED_WHEN, GROUP_CID) 
                          VALUES(SYSDATE, :JOB_ID, :CELL, :SN, :STEP_NAME, :STEP_TYPE, :START_SEQ, :END_SEQ, :CHECKEDINBY_EMP_CID, 'Y', null, 
                          null, null) RETURNING C_ID INTO :LASTCID";

        using (RetryClass RetryClassInstance = new RetryClass(this, JobSessionData, UserData))
        {
            do
            {
                RetryClassInstance.Retry = false;
                OracleConnection conn = new OracleConnection(Machine_Data.oracle_connstr);
                OracleCommand cmd = new OracleCommand(sqlStr, conn);
                try
                {
                    conn.Open();

                    foreach (string SN in JobSessionData.serial_numbers)
                    {
                        cmd.Parameters.Clear();
                        cmd.Parameters.Add("JOB_ID", JobSessionData.jobnumber);
                        cmd.Parameters.Add("CELL", JobSessionData.cell);
                        cmd.Parameters.Add("STEP_NAME", StepName);
                        cmd.Parameters.Add("STEP_TYPE", StepType);
                        cmd.Parameters.Add("START_SEQ", Start_Seq);
                        cmd.Parameters.Add("END_SEQ", End_Seq);
                        cmd.Parameters.Add("CHECKEDINBY_EMP_CID", UserData.employee_cid);
                        cmd.Parameters.Add("SN", SN);
                        cmd.Parameters.Add("LASTCID", OracleDbType.Int64, ParameterDirection.Output);

                        cmd.ExecuteNonQuery();

                        C_ID = cmd.Parameters["LASTCID"].Value.ToString();
                        C_IDS.Add(C_ID);
                    }

                }
                catch (Exception ex)
                {
                    RetryClassInstance.HadException(ex);
                }
                finally
                {
                    if (cmd != null) cmd.Dispose();
                    if (conn != null) conn.Dispose();
                }
            } while (RetryClassInstance.Retry == true);
        }

第二段代码返回的错误如下:

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at OracleInternal.TTC.TTCExecuteSql.ReceiveExecuteResponse(Accessor[]& defineAccessors, Accessor[] bindAccessors, Boolean bHasReturningParams, SQLMetaData& sqlMetaData, SqlStatementType statementType, Int64 noOfRowsFetchedLastTime, Int32 noOfRowsToFetch, Int32& noOfRowsFetched, Int64& queryId, Int32 longFetchSize, Int32 initialLOBFetchSize, Int64[] scnFromExecution, Boolean& bAllPureInputBinds, DataUnmarshaller& dataUnmarshaller, MarshalBindParameterValueHelper& marshalBindParamsHelper, Boolean bDefineDone, Boolean& bMoreThanOneRowAffectedByDmlWithRetClause)
   at OracleInternal.ServiceObjects.OracleCommandImpl.ExecuteNonQuery(String commandText, OracleParameterCollection paramColl, CommandType commandType, OracleConnectionImpl connectionImpl, Int32 longFetchSize, Int32 lobPrefetchSize, OracleDependencyImpl orclDependencyImpl, Int64[]& scnFromExecution, OracleParameterCollection& bindByPositionParamColl, Boolean& bBindParamPresent, Boolean isFromEF)
   at Oracle.ManagedDataAccess.Client.OracleCommand.ExecuteNonQuery()

两者都在同一个Oracle数据库实例上运行。如果我注释掉与OUTPUT PARAMETER相关的行并从SQL INSERT语句中删除返回子句,那么第二段代码就可以正常工作。

此外,LEI_CHECKIN_QUEUE表还有一个名为C_ID的列,它是主键。

有没有人知道为什么第二段代码不起作用和/或我可以做些什么来修复它?

谢谢!

4 个答案:

答案 0 :(得分:3)

您需要声明变量,如下所示。 根据经验,在将代码嵌入代码之前,请始终在Oracle服务器上测试查询。大多数,重要的是使用参数化存储过程来避免sql注入攻击。所以不要在你的代码中嵌入查询。

@"declare   LASTCID number;
INSERT INTO LEI_CHECKIN_QUEUE(CHECKIN_DATE, JOB_ID, CELL, SN, STEP_NAME, STEP_TYPE, START_SEQ,
                          END_SEQ, CHECKEDINBY_EMP_CID, IN_QUEUE, PRIORITY_CODE, STEP_STARTED_WHEN, GROUP_CID) 
                          VALUES(SYSDATE, :JOB_ID, :CELL, :SN, :STEP_NAME, :STEP_TYPE, :START_SEQ, :END_SEQ, :CHECKEDINBY_EMP_CID, 'Y', null, 
                          null, null) RETURNING C_ID INTO :LASTCID";

答案 1 :(得分:0)

在我看来,你做了一些额外的不需要的参数

cmd.Parameters.Add("SN", SN);

好习惯是使用&#34; BindByName = true&#34;初始化OracleCommand。 像

这样的东西
using (OracleCommand countCommand = new OracleCommand(strSql, connection) { CommandType = CommandType.Text, BindByName = true })
{...}

答案 2 :(得分:0)

当你在每行中使用“@”连接“\ n”时,你的结果字符串将

"INSERT INTO LEI_CHECKIN_QUEUE(CHECKIN_DATE, JOB_ID, CELL, SN,  \n STEP_NAME, STEP_TYPE, START_SEQ, END_SEQ, CHECKEDINBY_EMP_CID, \n IN_QUEUE, PRIORITY_CODE, STEP_STARTED_WHEN, GROUP_CID) \n VALUES(SYSDATE, :JOB_ID, :CELL, :SN, :STEP_NAME, :STEP_TYPE, \n :START_SEQ, :END_SEQ, :CHECKEDINBY_EMP_CID, 'Y', null, null, null) \n RETURNING C_ID INTO :LASTCID";

你应该使用

String sql = "INSERT INTO LEI_CHECKIN_QUEUE (CHECKIN_DATE, JOB_ID, CELL, SN, STEP_NAME, STEP_TYPE, START_SEQ,";
sql += "END_SEQ, CHECKEDINBY_EMP_CID, IN_QUEUE, PRIORITY_CODE, STEP_STARTED_WHEN, GROUP_CID)";
sql += "VALUES (SYSDATE,: JOB_ID,: CELL: SN: STEP_NAME,: STEP_TYPE,: START_SEQ,: END_SEQ,: CHECKEDINBY_EMP_CID, 'Y', null,";
sql += "null, null) C_ID RETURNING INTO: LASTCID";

答案 3 :(得分:0)

这是一篇很老的帖子,但Dan Hunex's answer帮助我解决了我的问题。我必须更正式,使用Oracle.ManagedDataAccess,但基本上我的问题是相同的,在我的情况下你的查询看起来像这样:

DECLARE
    LASTCID number;
BEGIN
    INSERT INTO LEI_CHECKIN_QUEUE(CHECKIN_DATE, JOB_ID, CELL, SN, STEP_NAME, STEP_TYPE, START_SEQ,
                      END_SEQ, CHECKEDINBY_EMP_CID, IN_QUEUE, PRIORITY_CODE, STEP_STARTED_WHEN, GROUP_CID) 
                      VALUES(SYSDATE, :JOB_ID, :CELL, :SN, :STEP_NAME, :STEP_TYPE, :START_SEQ, :END_SEQ, :CHECKEDINBY_EMP_CID, 'Y', null, 
                      null, null) RETURNING C_ID INTO :LASTCID;
END;
相关问题