#1 2015-08-30 09:35:07

trx
Member
Registered: 2015-08-30
Posts: 30

TSQLRecord with an object that has a TObjectList

Hi,

I have a TSQLRecord like so :

  TMzItem = class(TSQLRecordWithNames)
  protected
    FDescriptions : TMzNameList;
    FImages       : TMzImageList;
  public
    constructor Create; override;
    destructor Destroy; override;
  published
    property Descriptions : TMzNameList read FDescriptions write FDescriptions;
    property Images       : TMzImageList read FImages write FImages;
  end;

constructor TMzItem.Create;
begin
  inherited;
  FDescriptions := TMzNameList.Create;
  FImages := TMzImageList.Create;
end;

destructor TMzItem.Destroy;
begin
  FImages.Free;
  FDescriptions.Free;
  inherited;
end;

TMzNameList and TMzName look like :

  TMzName = class(TPersistentWithCustomCreate)
  private
    FName: RawUTF8;
    FLanguageID: TID;
  public
    constructor Create; overload; override;
    constructor Create(const AName : RawUTF8; const ALangID : TID); overload;
    function GetLanguage(const AClient : TSQLRest): TMzLanguage;
  published
    property LanguageID : TID read FLanguageID write FLanguageID;
    property Name : RawUTF8 read FName write FName;
  end;

  TMzNameList = class(TObjectList)
  protected
    function GetItem(Index: Integer): TMzName;
    procedure SetItem(Index: Integer; const Value: TMzName);
  public
    function Add(AObject: TMzName): Integer; inline;
    property Items[Index: Integer]: TMzName read GetItem write SetItem; default;
  end;

constructor TMzName.Create(const AName: RawUTF8; const ALangID: TID);
begin
  Create;
  FName := AName;
  FLanguageID := ALangID;
end;

constructor TMzName.Create;
begin
  inherited Create;
end;

function TMzName.GetLanguage(const AClient: TSQLRest): TMzLanguage;
begin
  Result := TMzLanguage.Create(AClient, FLanguageID);
end;

function TMzNameList.Add(AObject: TMzName): Integer;
begin
  inherited Add(TObject(AObject));
end;

function TMzNameList.GetItem(Index: Integer): TMzName;
begin
  Result := TMzName(inherited Items[Index]);
end;

procedure TMzNameList.SetItem(Index: Integer; const Value: TMzName);
begin
  inherited Items[Index] := TObject(Value);
end;

initialization

  TJSONSerializer.RegisterClassForJSON([TMzName]);

When i create a TMzItem with some Descriptions they are saved just fine. The problem is with TMzImageList :

  TMzImage = class(TPersistentWithCustomCreate)
  protected
    FId : integer;
    FNames : TMzNameList;
    FIsDefault : boolean;
    FIsVisible : boolean;
  public
    constructor Create; overload; override;
    constructor Create(const AId : integer; const AIsDefault : Boolean; const AIsVisible : Boolean); reintroduce; overload;
    destructor Destroy; override;
  published
    property Names     : TMzNameList read FNames write FNames;
    property ID        : integer read FId write FId;
    property IsDefault : boolean read FIsDefault write FIsDefault;
    property IsVisible : boolean read FIsVisible write FIsVisible;
  end;

  TMzImageList = class(TObjectList)
  protected
    function GetItem(Index: Integer): TMzImage;
    procedure SetItem(Index: Integer; const Value: TMzImage);
  public
    function Add(AObject: TMzImage): Integer; inline;
    property Items[Index: Integer]: TMzImage read GetItem write SetItem; default;
  end;

function TMzImageList.Add(AObject: TMzImage): Integer;
begin
  inherited Add(TObject(AObject));
end;

function TMzImageList.GetItem(Index: Integer): TMzImage;
begin
  Result := TMzImage(inherited Items[Index]);
end;

procedure TMzImageList.SetItem(Index: Integer; const Value: TMzImage);
begin
  inherited Items[Index] := TObject(Value);
end;

constructor TMzImage.Create(const AId: integer; const AIsDefault, AIsVisible: Boolean);
begin
  Create;
  FNames := TMzNameList.Create;
  FId := AId;
  FIsDefault := AIsDefault;
  FIsVisible := AIsVisible;
end;

constructor TMzImage.Create;
begin
  inherited Create;
end;

destructor TMzImage.Destroy;
begin
  FNames.Free;
  inherited;
end;

initialization

  TJSONSerializer.RegisterClassForJSON([TMzImage]);

When i add some TMzImage to Images of TMzItem they are not saved. Instead that property is empty ('[]'). If i remove Names from TMzImage, then Images are saved properly. I have tried to debug Client.Add(item, True) and i can see that the TMzItem is properly converted to JSON along with its images and their names but not saved as such. Images is [].

Have you any suggestions?

Thank you.

trx.

Offline

#2 2015-08-30 11:56:54

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,207
Website

Re: TSQLRecord with an object that has a TObjectList

How would the serialization know the type of each item of the TObjectList?
There is not such information available.

Please check the doc:

...
// - won't handle TObjectList (even if ObjectToJSON is able to serialize
// them) since has no way of knowing the object type to add (TCollection.Add
// is missing), unless: 1. you set the TObjectListItemClass property as expected,
// and provide a TObjectList object, or 2. woStoreClassName option has been
// used at ObjectToJSON() call and the corresponding classes have been previously
// registered by TJSONSerializer.RegisterClassForJSON() (or Classes.RegisterClass)
...
function JSONToObject(var ObjectInstance; From: PUTF8Char; var Valid: boolean;
  TObjectListItemClass: TClass=nil; Options: TJSONToObjectOptions=[]): PUTF8Char;

See http://synopse.info/files/html/api-1.18 … ONTOOBJECT

The alternative are, as documented:
- Define TCollection/TCollectionItem types;
- Use a T*ObjArray dynamic array type, registered via TJSONSerializer.RegisterObjArrayForJSON - see http://synopse.info/files/html/api-1.18 … RAYFORJSON

In fact, T*ObjArray are just great, and automatically allocated/released if your owning class is a TPersistentAutoCreateFields or a TSynAutoCreateFields.
See http://synopse.info/files/html/api-1.18 … EATEFIELDS

Offline

Board footer

Powered by FluxBB