#1 2015-07-27 07:15:12

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

TObjectList<T> as a service method parameter

Hello,

I have the following code:

  TMeasurementJob = class(TSynPersistent)
  private
    fMeasurements: TObjectList<TMeasurement>;
  protected
    procedure SetMeasurements(const aValue: TObjectList<TMeasurement>);
  public
    constructor Create;
    destructor Destroy; override;
  published
    property Measurements: TObjectList<TMeasurement> read fMeasurements write SetMeasurements;
  end;

constructor TMeasurementJob.Create;
begin
  fMeasurements := TObjectList<TMeasurement>.Create(True);
end;  

destructor TMeasurementJob.Destroy;
begin
  fMeasurements.Free;
  inherited;
end;

initialization
  TJSONSerializer.RegisterClassForJSON([TMeasurementJob, TMeasurement]);

Now, I create a service:

  IJobService = interface(IInvokable)
  ['{4CAE54FA-2371-40D9-9FD4-DEC80A34803D}']
    function SaveMeasurementJob(const aJob: TMeasurementJob): Boolean;
  end;

There is the following code in a delphi client:

    aJob := TMeasurementJob.Create;

    for I := 0 to 2 do
      aJob.Measurements.Add(TMeasurement.Create);

    aJob.Free;

    ...

    fJobService.SaveMeasurementJob(aJob);

And the problem is that on the server side the Job-Object doesn't contain any measurements, i.e. the list aJob.Measurements is empty.

My server and client are ClientDriven.

What am I doing wrong?

Thx for the answer!

Offline

#2 2015-07-27 11:21:08

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 13,048
Website

Re: TObjectList<T> as a service method parameter

TObjectList<TMeasurement> is not handled yet.
It is very difficult to retrieve the actual internal type of a generic type, even with enhanced RTTI.

Use T*ObjArray instead.
See http://synopse.info/files/html/Synopse% … #TITLE_555

Offline

#3 2015-07-28 12:34:43

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: TObjectList<T> as a service method parameter

ab wrote:

TObjectList<TMeasurement> is not handled yet.
It is very difficult to retrieve the actual internal type of a generic type, even with enhanced RTTI.

Use T*ObjArray instead.
See http://synopse.info/files/html/Synopse% … #TITLE_555

Just want to know if my code is fine and doesn't have any memory leaks. I've changed my code as follows.

My custom data types:

  TMeasurements = array of TMeasurement;

  TMeasurementJob = class(TSynPersistent)
  private
    fMeasurements: TMeasurements;
  protected
    procedure SetMeasurements(const aValue: TMeasurements);
  published
    property Measurements: TMeasurements read fMeasurements write SetMeasurements;
  end;

initialization
  TJSONSerializer.RegisterClassForJSON([TMeasurementJob, TMeasurement]);
  TJSONSerializer.RegisterObjArrayForJSON([TypeInfo(TMeasurements), TMeasurement]);

Usage:

// client side
procedure SendDataToServer;
var
  Measurements: TMeasurements;
  aMeasurement: TMeasurement;
begin
  aJob := TMeasurementJob.Create;
  try
    for I := 0 to 10 do
    begin
      aMeasurement := TMeasurement.Create;
      ...
      ObjArrayAdd(Measurements, aMeasurement);
    end;
    
    aJob.Measurements := Measurements;
    
    // send data to the server
    fJobService.SaveMeasurementJob(aJob);

  finally
    ObjArrayClear(Measurements);
    aJob.Free;
  end;  
end;

Is it possible to avoid the additional declaration of the *Measurements: TMeasurements;* and to add the aMeasurement objects directly to the Measurement property of the aJob object?

Offline

#4 2015-07-28 12:43:23

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: TObjectList<T> as a service method parameter

In future I would like to extend the TMeasurement class by a new property Data: TSQLRawBlob.
The client could define then about 250 000 TMeasurement objects and send it through the service to the server. The amount of the data in one TSQLRawBlob property could be up to 1 MB. Could you please advise me how I can handle it with the mORMot framework in the best and proper way?

Thank you for your time and help in advance! :-)

Offline

#5 2015-07-28 15:19:25

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 13,048
Website

Re: TObjectList<T> as a service method parameter

Any BLOB would be transmitted as Base64 encoded, so is not very efficient.

In your previous code, instead of calling ObjArrayAdd(), you may just use SetLength() before the loop, since you know how many items there will be, then fill each array item.
It would be slightly faster than ObjArrayAdd(), which is re-allocating the array length at each call.

Offline

#6 2015-07-28 18:47:21

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: TObjectList<T> as a service method parameter

ab wrote:

Any BLOB would be transmitted as Base64 encoded, so is not very efficient.

What would you recommend to do instead of it in order to get the efficiency?


ab wrote:

In your previous code, instead of calling ObjArrayAdd(), you may just use SetLength() before the loop, since you know how many items there will be, then fill each array item.
It would be slightly faster than ObjArrayAdd(), which is re-allocating the array length at each call.

Okay, I will do this. But what I actually wanted to know if it is possible to get rid of the declaration of "Measurements: TMeasurements;" and do directly ObjArraySetLength(aJob.Measurements, 3)? If I write this code, I get a compile error "Constant object cannot be passed as var parameter".

Is there another way?

Offline

#7 2015-07-28 19:20:54

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 13,048
Website

Re: TObjectList<T> as a service method parameter

For BLOB transfert, a method-based service is possible.
Or, only from server to client, use http://synopse.info/files/html/Synopse% … #TITLE_430

About the Measurements dynamic array, don't worry about using a local variable to use SetLength(), then assign the whole variable to the property.
It would use reference counting, so would be copied by reference, so would be immediate.

Offline

Board footer

Powered by FluxBB