You are not logged in.
Pages: 1
Dear ab,
when a TSQLRecord descendant contains a TObjectList of TSynPersistent descendant, which contains a TObjectList of another TSynPersistent descendant, I could not figure how to get the correct JSON representation of the TSQLRecord. Could you help to comment ? Many thanks !
When using the code at the end of this post, the incorrect JSON representation is obtained. Specifically, the info of the NestedObject is lost.
{
"ID": 1,
"OuterObjects":
[{
"ClassName":"TOuterObject"
},{
"ClassName":"TOuterObject"
}
]
}
program Project1;
{$APPTYPE CONSOLE}
uses
FastMM4,
SynCommons, SynLog, SynTests, SynSQLite3, SynSQLite3Static, mORMot, mORMotSQLite3,
Contnrs, SysUtils;
type
TNestedObject = class(TSynPersistent)
private
FDescription: RawUTF8;
published
property Description: RawUTF8 read FDescription write FDescription;
end;
TNestedObjectList = class(TObjectList)
protected
procedure SetObject (Idx: Integer; Item: TNestedObject);
function GetObject (Idx: Integer): TNestedObject;
public
function Add (Obj: TNestedObject): Integer;
procedure Insert (Idx: Integer; Obj: TNestedObject);
property Objects [Idx: Integer]: TNestedObject read GetObject write SetObject; default;
end;
TOuterObject = class(TSynPersistent)
private
FNestedObjects: TNestedObjectList;
public
property NestedObjects: TNestedObjectList read FNestedObjects write FNestedObjects;
constructor Create; override;
destructor Destroy; override;
end;
TOuterObjectList = class(TObjectList)
protected
procedure SetObject (Idx: Integer; Item: TOuterObject);
function GetObject (Idx: Integer): TOuterObject;
public
function Add (Obj: TOuterObject): Integer;
procedure Insert (Idx: Integer; Obj: TOuterObject);
property Objects [Idx: Integer]: TOuterObject read GetObject write SetObject; default;
end;
TSQLMainRecord = class(TSQLRecord)
private
FOuterObjects: TOuterObjectList;
public
constructor Create; override;
destructor Destroy; override;
published
property OuterObjects: TOuterObjectList read FOuterObjects write FOuterObjects;
end;
TTestManipulateNestedObjectList = class(TSynTestCase)
published
procedure AddNestedObjectList;
end;
TTestSuite = class(TSynTests)
published
procedure MyTestSuite;
end;
function TNestedObjectList.Add(Obj: TNestedObject): Integer;
begin
Result := inherited Add (Obj);
end;
procedure TNestedObjectList.Insert(Idx: Integer; Obj: TNestedObject);
begin
inherited Insert(Idx, Obj);
end;
procedure TNestedObjectList.SetObject(Idx: Integer; Item: TNestedObject);
begin
inherited SetItem (Idx, Item);
end;
function TNestedObjectList.GetObject(Idx: Integer): TNestedObject;
begin
Result := inherited GetItem (Idx) as TNestedObject;
end;
constructor TOuterObject.Create;
begin
inherited Create;
FNestedObjects := TNestedObjectList.Create(True);
end;
destructor TOuterObject.Destroy;
begin
FNestedObjects.Free;
inherited Destroy;
end;
function TOuterObjectList.Add(Obj: TOuterObject): Integer;
begin
Result := inherited Add (Obj);
end;
procedure TOuterObjectList.Insert(Idx: Integer; Obj: TOuterObject);
begin
inherited Insert(Idx, Obj);
end;
procedure TOuterObjectList.SetObject(Idx: Integer; Item: TOuterObject);
begin
inherited SetItem (Idx, Item);
end;
function TOuterObjectList.GetObject(Idx: Integer): TOuterObject;
begin
Result := inherited GetItem (Idx) as TOuterObject;
end;
constructor TSQLMainRecord.Create;
begin
inherited Create;
FOuterObjects := TOuterObjectList.Create(True);
end;
destructor TSQLMainRecord.Destroy;
begin
FOuterObjects.Free;
inherited Destroy;
end;
procedure TTestManipulateNestedObjectList.AddNestedObjectList;
var
ILog: ISynLog;
DBFileName: string;
Model: TSQLModel;
Rest: TSQLRest;
Rec: TSQLMainRecord;
RecID: Int64;
OuterObject: TOuterObject;
NestedObject: TNestedObject;
begin
ILog := TSynLog.Enter;
DBFileName := ChangeFileExt(ChangeFileExt(ExeVersion.ProgramFileName, '') +
'_' + FormatDateTime('yyyy_mm_dd_hh_nn_ss_zzz', Now),'.db3');
Model := TSQLModel.Create([TSQLMainRecord]);
try
Rest := TSQLRestClientDB.Create(Model, nil, DBFileName, TSQLRestServerDB, False);
try
TSQLRestClientDB(Rest).Server.CreateMissingTables;
Rec := TSQLMainRecord.Create;
try
OuterObject := TOuterObject.Create;
Rec.OuterObjects.Add(OuterObject);
NestedObject := TNestedObject.Create;
OuterObject.NestedObjects.Add(NestedObject);
NestedObject.Description := 'string 1';
NestedObject := TNestedObject.Create;
OuterObject.NestedObjects.Add(NestedObject);
NestedObject.Description := 'string 2';
OuterObject := TOuterObject.Create;
Rec.OuterObjects.Add(OuterObject);
NestedObject := TNestedObject.Create;
OuterObject.NestedObjects.Add(NestedObject);
NestedObject.Description := 'string 3';
RecID := Rest.Add(Rec, True);
Assert(RecID > 0, 'Error adding the data');
SynCommons.FileFromString(ObjectToJSON(Rec, [woHumanReadable]), 'Project1.json');
finally
Rec.Free;
end;
Rec := TSQLMainRecord.Create(Rest, RecID);
try
Check(Rec.OuterObjects.Count = 2);
Check(Rec.OuterObjects[0].NestedObjects.Count = 2);
Check(Rec.OuterObjects[0].NestedObjects[0].Description = 'string 1');
Check(Rec.OuterObjects[0].NestedObjects[1].Description = 'string 2');
Check(Rec.OuterObjects[1].NestedObjects.Count = 1);
Check(Rec.OuterObjects[1].NestedObjects[0].Description = 'string 3');
finally
Rec.Free;
end;
finally
Rest.Free;
end;
finally
Model.Free;
end;
end;
procedure TTestSuite.MyTestSuite;
begin
AddCase([TTestManipulateNestedObjectList]);
end;
begin
TJSONSerializer.RegisterClassForJSON([TOuterObject, TNestedObject]);
with TSynLog.Family do
begin
Level := LOG_VERBOSE;
PerThreadLog := ptIdentifiedInOnFile;
RotateFileCount := 5;
RotateFileSizeKB := 20*1024; // rotate by 20 MB logs
end;
with TTestSuite.Create do
begin
try
Run;
readln;
finally
Free;
end;
end;
end.
Offline
Try to set the woObjectListWontStoreClassName option.
Offline
Thank you for your efforts very much !
The woObjectListWontStoreClassName does not help. The generated JSON looks like below:
{
"ID": 1,
"OuterObjects":
[{
},{
}
]
}
More importantly, the nested object list can not be persisted by the ORM, as can be seen from the generated .db3 file.
Could you help to comment ?
Offline
It is found that my problem is actually caused by a mistake, i.e., forget to publish properties... It can be solved as shown below:
Thank you very much for your help !
TOuterObject = class(TSynPersistent)
private
FNestedObjects: TNestedObjectList;
published
property NestedObjects: TNestedObjectList read FNestedObjects write FNestedObjects;
public
constructor Create; override;
destructor Destroy; override;
end;
Offline
Pages: 1