Проблемы с возвратом курсора из хранимой процедуры как ClientDataset

Этот вопрос напрямую относится к моему Предыдущий вопрос.

Мне нужно создать TClientDataSet на клиенте из курсора Oracle 11g, содержащегося в пакете. Я использую Delphi XE2 и DBExpress для подключения к БД и DataSnap для отправки данных обратно клиенту.

Когда я настраиваю TSQLStoredProc на TClientDataset во время разработки, я могу без проблем вернуть курсор как TClientDataset и получить ожидаемые результаты.

Когда я пытаюсь выполнить хранимую процедуру во время выполнения, она возвращает пустой TClientDataset.

Можно ли настроить и выполнить хранимую процедуру Oracle 11g с помощью TSQLStoredProc во время выполнения?

Сервер DataSnap

Код модуля данных времени разработки [в виде текста]

    object StrProc1: TSQLStoredProc
    SchemaName = 'xxxx'
    MaxBlobSize = -1
    Params = <
      item
        DataType = ftWideString
        Precision = 2000
        Name = 'ABBR'
        ParamType = ptInput
        Value = 'ZZZTOP' 
      end
      item
        DataType = ftCursor
        Precision = 8000
        Name = 'RES'
        ParamType = ptOutput
        Size = 8000
      end>
    PackageName = 'KP_DATASNAPTEST'
    SQLConnection = SQLConnection1
    StoredProcName = 'GETFAXDATA'
    Left = 408
    Top = 72
  end
  object DataSetProvider1: TDataSetProvider
    DataSet = StrProc1
    Left = 408
    Top = 120
  end
  object ClientDataSet1: TClientDataSet
    Aggregates = <>
    Params = <>
    ProviderName = 'DataSetProvider1'
    Left = 408
    Top = 176
  end

функция для выполнения конфигурации времени разработки

function TKPSnapMethods.getCDS_Data3: OLEVariant;
begin    
 self.ClientDataSet1.Open;
 result:= self.ClientDataSet1.Data;
 self.SQLConnection1.Close;
end;

функция для выполнения конфигурации среды выполнения. Это код, который возвращает пустой ClientDataSet. Цель состоит в том, чтобы соединить части, установить значение параметра, открыть CDS и вернуть CDS.

function TKPSnapMethods.getCDS_Data2(schema: String): OleVariant;
var
  cds: TClientDataSet;
  dsp: TDataSetProvider;
  strProc: TSQLStoredProc;
  ProcParams: TList;
begin
  strProc := TSQLStoredProc.Create(self);
  try
    strProc.SQLConnection:= SQLCon;//<--A TSQLConnection    
    dsp := TDataSetProvider.Create(self);
    try
      dsp.DataSet := strProc;

      cds := TClientDataSet.Create(self);
      try
        cds.DisableStringTrim := True;
        cds.ReadOnly := True;
        cds.SetProvider(dsp);

        ProcParams:= TList.Create;    
        try
          //Load Stored Procedure Parameters
          SQLCon.GetProcedureParams('GETFAXDATA','KP_DATASNAPTEST',Schema,ProcParams);
          LoadParamListItems(StrProc.Params,ProcParams);
          
          strProc.ParamByName('ABBR').AsString := 'ZZZTOP';//<--Assign Parms
          strProc.MaxBlobSize := -1;
          strProc.SchemaName:= Schema;
          strproc.PackageName:='KP_DATASNAPTEST';
          strProc.StoredProcName:= 'GETFAXDATA';
          cds.Open;
          Result := cds.Data;
        finally
          FreeProcParams(ProcParams);
        end;
      finally
        FreeAndNil(cds);
      end;
    finally
      FreeAndNil(dsp);
    end;
  finally
    FreeAndNil(strProc);
    self.SQLCon.Close;
  end;
end;

Код клиента - это просто тестовая форма, которая создает соединение с DataSnap Server, выполняет ServerMethods и отображает результаты в виде строковой сетки.

procedure TForm1.Button1Click(Sender: TObject);
var
 proxy:TKpSnapMethodsClient;
 cds :TClientDataSet;
 field: TField;
 r,c:integer;
begin
  r:=0;
  c:=0;
  SQLConTCPSERV.Connected := True; //TSQLConnection
  proxy:= TKPSnapMethodsClient.Create(SQLConTCPSERV.DBXConnection,false);
  cds:= TClientDataSet.Create(nil);
  try
    //cds.Data:= proxy.getCDS_Data2('TESTTH');//<--Runtime function
    cds.Data:= proxy.getCDS_Data3; //<--Design time function
    if cds <> nil then
    begin
      cds.Open;
      cds.First;
      //String grid to display CDS contents.
      strGrid1.ColCount:= cds.FieldCount; //returns correct #
      strGrid1.RowCount:= cds.RecordCount;

      while not cds.Eof do  //<--runtime wont make it past here
      begin
        for field in cds.fields do //loop fields
        begin
          strgrid1.Cells[c,r]:= field.Text; //display results.
          c:=c+1;
        end;
        c:=0;
        r:=r+1;            
        cds.Next;
      end;
    end
    else showmessage('DataSet is NIL');
  finally
    cds.Free;
    proxy.Free;
    SQLConTCPSERV.Connected := False;
  end;
end;

Как только я должен признаться, я новичок в языке Delphi. Я безрезультатно искал документацию в Google, code.google, Embarcadero Developer Network и DBExpress. Я просто не понимаю, почему может быть разница между временем разработки и временем выполнения.


person Troy Harris    schedule 01.11.2012    source источник
comment
Пожалуйста, не включайте информацию тегов в тему ваших вопросов; Система тегов здесь разработана очень хорошо и работает без посторонней помощи. Кроме того, нет необходимости КРИЧАТЬ какую-либо информацию в вашем вопросе; даже если у нас могут быть проблемы со слухом, понимание прочитанного здесь, как правило, очень высокое, а текст, набранный ВСЕМИ ЗАГЛАВНЫМИ буквами, труднее читать (и довольно раздражает). Мы также рассмотрим ваш вопрос и без него. Спасибо.   -  person Ken White    schedule 02.11.2012
comment
Ваш вопрос довольно непонятный. Вы говорите, что время разработки работает, а среда выполнения - нет, но код в обработчике Button1Click на стороне клиента показывает два полностью отдельных вызова функций (getCDS_Data2('TESTTH1) и getCDS_Data3 (без параметра)) и говорит, что один из них работает, но вы показываете только код для getCDS_Data2. Трудно сравнить их и сказать, почему один работает, а другой нет, если вы не даете нам код для сравнения.   -  person Ken White    schedule 02.11.2012
comment
Я обновил заголовок, чтобы удалить теги и слова, начинающиеся с заглавных букв. Код для getCDS_Data3 включен, возможно, вы просто его не заметили. У вас есть идеи, почему функция будет работать во время разработки, а не во время выполнения? Спасибо   -  person Troy Harris    schedule 02.11.2012
comment
Вы правы. Я не заметил этого. Код для getCDS_Data2 составляет около сорока строк кода, а getCDS_Data3 - три; Думаю, я ожидал, что они будут более похожими, потому что вы хотели, чтобы мы объяснили различное поведение. Вы можете объяснить, как они сопоставимы? (Первая - это примерно в 13 раз больше кода, что, очевидно, означает, что каждая третья строка должна быть эквивалентной.)   -  person Ken White    schedule 02.11.2012
comment
Причина, по которой функции так сильно различаются, заключается в том, что функция getCDS_Data3 получает настройки своих компонентов из предоставленного кода времени разработки, в то время как функция getCDS_Data2 создает и устанавливает свои компоненты во время выполнения. Мне нужно выполнять хранимые процедуры во время выполнения, потому что неэффективно отбрасывать компонент в модуль данных для каждой хранимой процедуры, которую мне нужно выполнить. Я был бы очень признателен за любые комментарии относительно того, почему компонент будет вести себя по-разному во время выполнения и во время разработки. Спасибо   -  person Troy Harris    schedule 02.11.2012


Ответы (1)


Я решил проблему. проблема заключается в порядке присвоения значений компоненту TSQLStoredProc.

при вызове этого кода:

strproc.PackageName:='KP_DATASNAPTEST';
strProc.StoredProcName:= 'GETFAXDATA';

параметры очищаются. Ниже приведен код для установки StoredProcName, найденного в Data.SqlExpr.

procedure TSQLStoredProc.SetStoredProcName(Value: UnicodeString);
begin
  //if FStoredProcName <> Value then
  //begin
    FStoredProcName := Value;
    SetCommandText(Value);
    if Assigned(FProcParams) then  // free output params if any
      FreeProcParams(FProcParams);
  //end;
end;

Как вы можете видеть, если назначены FProcParams, то FreeProcParams - это вызов, который освобождает параметры. Поскольку я устанавливал StroredProcName после того, как я назначал значения параметров, код выполнялся с очищенными параметрами и возвращал пустой курсор.

порядок, который дает правильные результаты во время выполнения [из getCDS_Data2], следующий:

strProc.SchemaName:= Schema;
SQLCon.GetProcedureParams('GETFAXDATA','KP_DATASNAPTEST',Schema,ProcParams);
LoadParamListItems(StrProc.Params,ProcParams);

strproc.PackageName:='KP_DATASNAPTEST';
strProc.StoredProcName:= 'GETFAXDATA';
strProc.MaxBlobSize := -1;
strProc.ParamCheck:=true;

strProc.ParamByName('ABBR').AsString := 'ZZZTOP';

cds.Open;
person Troy Harris    schedule 02.11.2012
comment
Мне кажется странным, что установка свойства объекта сильно повлияет на другой атрибут объекта. Я спишу это на новую кривую изучения языка. - person Troy Harris; 02.11.2012