我正在尝试插入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的列,它是主键。
有没有人知道为什么第二段代码不起作用和/或我可以做些什么来修复它?
谢谢!
答案 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;