Передача огромного XML из C # /. Net в хранимую процедуру Oracle через параметр CLOB - ORA-01008: не все переменные связаны - PullRequest
6 голосов
/ 31 июля 2010

Окружающая среда:

Сервер: Сервер Oracle 11.2g на 64-битных окнах 2008

Клиент: Клиент Oracle 11g в Windows XP SP3, ASP.Net 4.0, Visual Studio 2010, C #

Размер ввода XML ~ 1 206 500 символов (Рассчитано на основе максимальных данных, которые у меня будут).

Сценарий:

Веб-приложение генерирует XML, который хранимая процедура Oracle использует для обновления таблицы в базе данных. Поскольку размер XML довольно велик, выбранный тип параметра хранимой процедуры - CLOB вместо LONG, поскольку ограничение LONG составляет 32760 символов.

Проблема:

Использование CLOB в качестве типа параметра вызывает ошибку «ORA-01008: не все переменные связаны» для того же кода хранимой процедуры, который отлично работает для типа параметра LONG (и длина XML <32760) </p>

C # Код для вызова хранимой процедуры:

OracleCommand DbUpdateCommand = null;
OracleLob tempLOB = null;

DbUpdateCommand.CommandText = "declare xx clob; begin dbms_lob.createtemporary(xx, false, 0); :tempclob := xx; end;";
DbUpdateCommand.Parameters.Add(new OracleParameter("tempclob", OracleType.Clob)).Direction = ParameterDirection.Output;
DbUpdateCommand.ExecuteNonQuery();

//Assign the value to the LOB
tempLOB = (OracleLob)DbUpdateCommand.Parameters[0].Value;
tempLOB.BeginBatch(OracleLobOpenMode.ReadWrite);

//Convert the string to byte array to write to LOB
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] renewalDetailXMLBytes = encoding.GetBytes(renewalDetailXML);
tempLOB.Write(renewalDetailXMLBytes, 0, renewalDetailXMLBytes.Length);
tempLOB.EndBatch();

DbUpdateCommand.CommandText = "P_WEB_PRDCR_RNEW_UPDT";
DbUpdateCommand.CommandType = System.Data.CommandType.StoredProcedure;
DbUpdateCommand.Parameters.Add("PN_KEY_AGNT_RNEW_HDR", 
System.Data.OracleClient.OracleType.Number, 12).Value = agentRenewalHeader;
DbUpdateCommand.Parameters.Add("PN_KEY_CO", 
System.Data.OracleClient.OracleType.Number, 12).Value = companyCode;
DbUpdateCommand.Parameters.Add("PC_RNWL_DETL_XML", 
    System.Data.OracleClient.OracleType.Clob).Value = tempLOB;
DbUpdateCommand.Parameters.Add("PS_USR_NM",
System.Data.OracleClient.OracleType.VarChar,255).Value = userName;

DbUpdateCommand.ExecuteNonQuery();

Код хранимой процедуры Oracle:

CREATE OR REPLACE PROCEDURE DOIADMIN.P_WEB_PRDCR_RNEW_UPDT (
    PN_KEY_AGNT_RNEW_HDR IN NUMBER,
    PN_KEY_CO            IN NUMBER,
    PC_RNWL_DETL_XML     IN CLOB,
    PS_USR_NM            IN VARCHAR2
)
AS
        lx_rnew_detl_xml    XMLTYPE;
    lct_rnew_detl_cntx  DBMS_XMLSAVE.ctxtype;

    --Construct the complete xml for financial data
    lx_rnew_detl_xml := XMLTYPE(PC_RNWL_DETL_XML);

    --table to be updated with the xml
    lct_rnew_detl_cntx := DBMS_XMLSAVE.newcontext('IL_AGNT_RNEW_DETL');

    --Set the key column list
    DBMS_XMLSAVE.SETKEYCOLUMN(lct_rnew_detl_cntx, 'KEY_AGNT_RNEW_HDR');
    DBMS_XMLSAVE.SETKEYCOLUMN(lct_rnew_detl_cntx, 'KEY_CO');
    DBMS_XMLSAVE.SETKEYCOLUMN(lct_rnew_detl_cntx, 'KEY_INDVDL_LIC');

    --Set the udpate column
    DBMS_XMLSAVE.SETUPDATECOLUMN(lct_rnew_detl_cntx, 'FLG_MARKED_FOR_CANCEL');

    --update the table from the rows
    ln_cntr := DBMS_XMLSAVE.UPDATEXML(lct_rnew_detl_cntx, lx_rnew_detl_xml.getCLOBVal());

    DBMS_XMLSAVE.closecontext(lct_rnew_detl_cntx);
END p_web_prdcr_rnew_updt;

Кто-нибудь, кто работал с передачей большого XML через параметр CLOB и преобразовал этот CLOB в XML в хранимой процедуре, может помочь? Любой альтернативный подход к этой проблеме также будет высоко оценен.

Заранее спасибо.

1 Ответ

2 голосов
/ 03 августа 2010

Вот код C #, который исправил проблему. Мне не хватало для очистки параметров перед повторным использованием одного и того же объекта команды.

C # код

OracleCommand DbUpdateCommand = null;
OracleLob tempLOB = null;

DbUpdateCommand.CommandText = "declare xx clob; begin dbms_lob.createtemporary(xx, false, 0); :tempclob := xx; end;";
DbUpdateCommand.Parameters.Add(new OracleParameter("tempclob", OracleType.Clob)).Direction = ParameterDirection.Output;
DbUpdateCommand.ExecuteNonQuery();

//Assign the value to the LOB
tempLOB = (OracleLob)DbUpdateCommand.Parameters[0].Value;
tempLOB.BeginBatch(OracleLobOpenMode.ReadWrite);

//Convert the string to byte array to write to LOB
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] renewalDetailXMLBytes = encoding.GetBytes(renewalDetailXML);
tempLOB.Write(renewalDetailXMLBytes, 0, renewalDetailXMLBytes.Length);
tempLOB.EndBatch();

DbUpdateCommand.CommandText = "P_WEB_PRDCR_RNEW_UPDT";
DbUpdateCommand.CommandType = System.Data.CommandType.StoredProcedure;

//Missing line - start
DbUpdateCommand.Parameters.Clear();
//Missing line - end

DbUpdateCommand.Parameters.Add("PN_KEY_AGNT_RNEW_HDR", 
    System.Data.OracleClient.OracleType.Number, 12).Value = 
        agentRenewalHeader;
DbUpdateCommand.Parameters.Add("PN_KEY_CO", 
    System.Data.OracleClient.OracleType.Number, 12).Value = 
        companyCode;
DbUpdateCommand.Parameters.Add("PC_RNWL_DETL_XML", 
    System.Data.OracleClient.OracleType.Clob).Value =
        tempLOB;
DbUpdateCommand.Parameters.Add("PS_USR_NM",
    System.Data.OracleClient.OracleType.VarChar,255).Value = 
        userName;

DbUpdateCommand.ExecuteNonQuery();
...