Population of input parameters of TDARemoteCommand

Hi,

I started using RemObjects products 20 years ago (RemObjects SDK).

Eventually, I used RemObjects Data Abstract (I was doing something similar with SDK creating my own servers and using TClientDataSet).

I’m not sure now, but after using AnyDAC, FireDAC, and UniDAC for many years, in addition to RO DA, I’m not sure of the features I had at my disposal.

The reality is that I got used to create stored procedures in my data modules capable of extracting all the information from the database (parameters, name, types).

I found strange that now DA only creates datasets (tables and datasources), missing the “TDARemoteCommand” with all the properties already captured by Relativity Server, or easily received from the database itself.

Are you leaving Delphi behind, and that feature is available on other platforms?

David

Hi,

You can drop Stored Procedures (SP) to Tables or Commands sections inside Schema Modeler.

if your SP returns select (i.e. table) - you should drop it to Tables, it values - to Commands sections.

Remote Command exists in .NET and Delphi platforms.

Hi,

My stored procedure returns parameters (OUT), not a dataset.

It is not a function, just a procedure with parameters.

Some of them with input and output parameters, others with input parameters, and one with a single out parameter.

Of course, SQL Server always return the RESULT_VALUE, in addition to my parameter.

I had to do this:

        var cmdGetLastMessageID : TDARemoteCommand := TDARemoteCommand.Create(nil);
        cmdGetLastMessageID.RemoteService := RemoteService;

        var opa : DataParameterArray := nil;
        try
            cmdGetLastMessageID.Execute('GetLastMessageID', nil, opa);

            Result := opa[1].Value
        finally
            opa.Free
        end

If I need to use input parameters, the code will be much more than that.

It should be easier, just by populating them when importing the definitions from Relativity Server or the database.

David

Hi,

you can use this helper:

type
  TDABaseCommand_helper = class helper for TDABaseCommand
  public
    function GenerateInputParameters(aSchema: TDAClientSchema; aCommandName: string): DataParameterArray;
  end;


{ TDABaseCommand_helper }

function TDABaseCommand_helper.GenerateInputParameters(aSchema: TDAClientSchema; aCommandName: string): DataParameterArray;
var
  l_command: TDASQLCommand;
  i: Integer;
begin
  Result := nil;
  l_command:= aSchema.Commands.SQLCommandByName(aCommandName);
  for i := 0 to l_command.Params.Count - 1 do begin
    if l_command.Params[i].ParamType in [daptInput, daptInputOutput] then begin
      if Result = nil then Result := DataParameterArray.Create;
      Result.Add.Name := l_command.Params[i].Name;
    end;
  end;
end;

usage:

  l_input :=  DARemoteCommand1.GenerateInputParameters(DARemoteDataAdapter1.Schema, 'MyCommand');

Thanks!

If that same code was used in a similar way to “Get Design Data”, it could make things even easier because saving the component will leave it available at design-time.

David

Hi,

Current TDARemoteCommand is designed for launching any server-side method.
I mean, if you add , say, MyExecuteCommand - it also can be executed.

We’ll review this possibility.

The latest DA build 10.0.0.1571 broke the previous behavior for executing TDARemoteCommand. My previous code executed correctly as:
var outParam : DataParameterArray := nil;
MyRemoteCommand.Execute(‘MyCommand’, nil, outputParam);
Now, I had to create an inputParam:
var inputParam : DataParameterArray := DataParameterArray.Create;
I don’t have any input parameter, and the output parameters could be inferred by using the suggested helper (which I did).

Hi,

what version of DataAbstract you have used before upgrading to .1571?

I was using build 1559/1569.

Hi,

TDARemoteCommand component wasn’t changed for latest 5 years.

If you look at the conversation, I was having some issues with TDARemoteCommand because I was used to the very old behavior of receiving it with all the design-time data imported from the schema. The code you suggested worked for me, executing it like

Execute(‘MyCommand’, nil, opa).

I have been using it for the past two weeks, but now I got an access violation.

It was triggered in this method:

procedure TDARemoteCommand.FillCommandParams(aDataParameterArray: DataParameterArray; aCommandParam: TRORequestParam);
var
  lArray: DataParameterArray;
  lParam: DataParameter;
  i: Integer;
begin
  if (aCommandParam.DataType <> rtUserDefined) or (aCommandParam.TypeName <> 'DataParameterArray') then Exit;

  lArray := DataParameterArray.Create();

  for i := 0 to aDataParameterArray.Count - 1 do begin <== Here aDataParameterArray is nil
    lParam := lArray.Add();
    lParam.Name := aDataParameterArray[i].Name;
    lParam.Value := aDataParameterArray[i].Value;
  end;

  aCommandParam.AsComplexType := lArray;
  aCommandParam.OwnsComplexType := True;
end;

What is interesting about this error is that it happens because of something strange:

function TDARemoteCommand.Execute(aCommandName: string;
  aInputParameters: DataParameterArray;
  out aOutputParameters: DataParameterArray): Integer;
var
  lParam: TRORequestParam;
begin
  Result := 0;
  aOutputParameters := nil;
  DAError(not Assigned(fExecuteCall), err_ExecuteCallIsUnassigned);
  if (Length(fExecuteCall.OutgoingCommandNameParameter) > 0) then
    fExecuteCall.ParamByName(fExecuteCall.OutgoingCommandNameParameter).Value := aCommandName;
  if (Length(fExecuteCall.OutgoingParametersParameter) > 0) then begin
    lParam := fExecuteCall.Params.FindParam(fExecuteCall.OutgoingParametersParameter); <== This is the issue
    if Assigned(lParam) then FillCommandParams(aInputParameters, lparam);
  end;

I don’t have any input parameters, just output parameters. That call shouldn’t assume there is an input parameter at all, as they are not required by all stored procedures.

In any case, I didn’t change my code until it failed. It is now working.

David

Hi,

update uDARemoteCommand.pas as

procedure TDARemoteCommand.FillCommandParams(aDataParameterArray: DataParameterArray; aCommandParam: TRORequestParam);
...
  lArray := DataParameterArray.Create();
  if Assigned(aDataParameterArray) then  //<<<<<<<<< added
    for i := 0 to aDataParameterArray.Count - 1 do begin

Logged as bugs://D19393.

bugs://D19393 was closed as fixed.