Как вернуть Oracle Cursor из хранимой процедуры в качестве клиентского набора данных с помощью Delphi и DBExpress

Во-первых, я все еще немного зеленый для Delphi, так что это может быть «приземленная деталь», которую упускают из виду. [извините заранее]

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

У меня проблемы с выполнением хранимой процедуры из кода Delphi.

Заголовок пакета:

create or replace
PACKAGE KP_DATASNAPTEST AS 
  procedure GetFaxData(abbr varchar2, Res out SYS_REFCURSOR);
END KP_DATASNAPTEST; 

Тело пакета:

create or replace
PACKAGE  body KP_DATASNAPTEST AS 
  procedure GetFaxData(abbr varchar2, Res out SYS_REFCURSOR)is
  Begin
    open Res for 
      SELECT  Name, 
              Address1, 
              City, 
              fax_nbr 
      FROM    name 
      JOIN phone on name.Abrv = phone.abrv 
      WHERE phone.fax_nbr is not null and name.abrv = abbr;
  end;
END KP_DATASNAPTEST;

У меня нет проблем с выполнением этой процедуры в SQL Developer, проблема заключается в этом коде на сервере DataSnap:

function TKPSnapMethods.getCDS_Data2(): OleVariant;
var
  cds: TClientDataSet;      
  dsp: TDataSetProvider;
  strProc: TSQLStoredProc;      
begin
  strProc := TSQLStoredProc.Create(self);
  try
    strProc.MaxBlobSize := -1;
    strProc.SQLConnection:= SQLCon;//TSQLConnection

    dsp := TDataSetProvider.Create(self);
    try
      dsp.ResolveToDataSet := True;
      dsp.Exported := False;
      dsp.DataSet := strProc;
      cds := TClientDataSet.Create(self);
      try
        cds.DisableStringTrim := True;
        cds.ReadOnly := True;
        cds.SetProvider(dsp);

        strProc.Close;
        strProc.StoredProcName:= 'KP_DATASNAPTEST.GetFaxData';
        strProc.ParamCheck:= true;
        strProc.ParamByName('abbr').AsString:= 'ZZZTOP';
        strProc.Open; //<--Error: Parameter 'Abbr' not found. 

        cds.Open;
        Result := cds.Data;
      finally
        FreeAndNil(cds);
      end;
    finally
      FreeAndNil(dsp);
    end;
  finally
    FreeAndNil(strProc);
    self.SQLCon.Close;
  end;
end;

Я также безуспешно пытался присвоить значение параметра через ClientDataSet. Я бы не стал возвращать TDataSet из функции, если это проще или дает результаты. Данные используются для заполнения настраиваемых атрибутов объекта.


person Troy Harris    schedule 24.10.2012    source источник
comment
Я смог получить эту функциональность, перетащив компоненты в модальное окно данных и установив статическое соединение с БД через: TCLientDataSet.ProviderName-> TDataSetProvider.Dataset-> TSQLStoredProc.SQLConnection -> TSQLConnection TSQLStoredProc.PackageName -> 'KP_DATASNAPTEST' TSQLStoredProc.StoredProcName -> 'GETFAXDATA' TSQLStoredProc.Params.ABBR -> 'ZZZTOP' Функция привязки данных просто открывает ClientDataset, возвращает ClientDataSet.Data, а затем закрывает соединение. Как-то мне нужно сделать это более динамичным.   -  person Troy Harris    schedule 25.10.2012


Ответы (2)


Как упоминалось paulsm4 в this answer, Delphi не заботится о получении дескрипторов параметров хранимой процедуры, поэтому вам нужно себя. Чтобы получить параметры хранимой процедуры Oracle из пакета, вы можете попробовать использовать GetProcedureParams для заполнения списка дескрипторами параметров и LoadParamListItems заполняет этот список Params коллекция. В коде это может выглядеть следующим образом.

Обратите внимание, что следующий код был написан только в браузере в соответствии с документацией, поэтому он не тестировался. И да, об освобождении переменной ProcParams это делается с помощью FreeProcParams процедура:

var
  ProcParams: TList;
  StoredProc: TSQLStoredProc;
  ...
begin
  ...
  StoredProc.PackageName := 'KP_DATASNAPTEST';
  StoredProc.StoredProcName := 'GetFaxData';
  ProcParams := TList.Create;
  try
    GetProcedureParams('GetFaxData', 'KP_DATASNAPTEST', ProcParams);
    LoadParamListItems(StoredProc.Params, ProcParams);
    StoredProc.ParamByName('abbr').AsString := 'ZZZTOP';
    StoredProc.Open;
  finally
    FreeProcParams(ProcParams);
  end;
  ...
end;
person TLama    schedule 25.10.2012
comment
Это исправило ошибку «Параметр не найден». как только я добавил StoredProc.PackageName := 'KP_DATASNAPTEST'; StoredProc.StoredProcName := 'GetFaxData'; после предложенного исправления. Теперь я возвращаю пустой ClientDataSet, когда пытаюсь присвоить все значения во время выполнения. если я сделаю это во время разработки, я получу ожидаемые результаты. - person Troy Harris; 25.10.2012

Я не думаю, что Delphi автоматически распознает имена параметров Oracle и заполнит их для вас. Я думаю, вам нужно добавить параметры. Например:

with strProc.Params.Add do
 begin
   Name := 'abbr';
   ParamType := ptInput;
   Value := ZZZTOP';
   ...
 end;
person paulsm4    schedule 25.10.2012
comment
Гораздо безопаснее и лучше для обслуживания использовать GetProcedureParams. и методы LoadParamListItems. [+1 в любом случае] - person TLama; 25.10.2012
comment
Это решение также решило проблему, связанную с тем, что параметр не найден. однажды я позвонил StoredProc.PackageName := 'KP_DATASNAPTEST'; StoredProc.StoredProcName := 'GetFaxData'; после params.add. У меня все еще есть проблема в том, что мой ClientDataSet пуст, когда я устанавливаю все во время выполнения. Если я свяжу все компоненты во время разработки, я получу ожидаемые результаты. Любые идеи??? - person Troy Harris; 25.10.2012