You are not logged in.
Hi,
I am trying to find out what I need to do to implement a class with a property of TOBjectList.
My classes looks like
TSQLPlayer = class(TSQLRecord)
...
end;
TListPlayer = TObjectList<TSQLPlayer>;
TSQLGame = class(TSQLRecord)
private
fPlayers:TListPlayer;
...
published
property Players:TListPlayer read fPlayers write fPlayers;
end;
This codes compiles with no errors; But in runtime I get the following exception:
EORMException with message 'Unhanled type for property Players'.
This happens in TSQLModel.Create([TSQLGame, TSQLPlayer], 'root');
Did I failed to do some initialization here?
Merci,
Wai
fpcdeluxe, FPC 3.2 / Lazarus 2.0, mORMot on Windows 10 ...
Offline
Please take a look at the SAD pdf (ensure you get the latest 1.18 revision), about one-to-many relationship in mORMot.
TObjectList is not handled as such.
In short, you have several options, and the better is IMHO data sharding, i.e. using a dynamic array and not a TObjectList.
Offline
I think I've read everything about it in the SAD, but probably missed something while searching for TObjectList in the doc. This topic is somewhat
related to http://synopse.info/forum/viewtopic.php?id=1372?
Off topic, but here is something for you :-) http://www.thestupidstation.com/home/im … nd-Marmots.
fpcdeluxe, FPC 3.2 / Lazarus 2.0, mORMot on Windows 10 ...
Offline
Hi Arnaud,
This one sounds stupid (hope I am not wrong), but is there an example of an implementation
of data sharding (in terms of CRUD operations)?
I have changed my TObjectList to a dynamic array. TListPlayer = TObjectList<TSQLPlayer>; is now changed to TListPlayer = array of TSQLPlayer;
I assume this is the correct way, but my ORM update fails .i.e. calling fMormot.Update (where fMormot is a TSQLRestServer).
My code looks like
TSQLGame = class(TSQLRecord)
...
published
fPlayers:TListPlayer;
end;
aGame := TSQLGame.CreateAndFillPrepare(fMormot, 'GameIdentifier=?', [aGameIdentifier]);
try
if not assigned(aGame) then
aStatus := cstStatusGameNotFound
else begin
aPlayer := TSQLPlayer.CreateAndFillPrepare(fMormot, 'ID=?', [aPlayerID]);
if not assigned(aPlayer) then
aStatus := cstStatusPlayerNotFound
else begin
aStatus := aGame.AddPlayer(aPlayer); <<<--- adds a TSQLPlayer object to the array fPlayers
if aStatus <> cstStatusGameIsFull then begin
if fMormot.Update(aGame) then begin <<<--- this returns false!
Hope this picture is clear.
fpcdeluxe, FPC 3.2 / Lazarus 2.0, mORMot on Windows 10 ...
Offline
Your dynamic array should be a dynamic array of records, not a dynamic array of class instances.
So it won't work as you expect here.
You need either:
- use a dynamic array of integers, containing the TSQLPlayer IDs
- use a many-to-many relationship (see the SAD pdf)
- change the TSQLPlayer from a TSQLRecord into a record, then use a dynamic array of records
Offline
Hello.
Is this still the case? On page 112 of SAD 1.18 it says "The following published properties types are handled by the ORM..." and lists TObjectList.
Or am I misunderstanding it?
Offline
TObjectList does not define the class type to be serialized.
So it may be difficult to unserialize it afterwards.
It should work in some cases, but you need to register the classes before.
What works straightly is to use a TCollection, or a dynamic array of records.
Offline
I would really like to use TObjectList as it makes LiveBindings easier for nested (sharded?) objects.
I have my objects defined as this and register the ITem class:
uses mORMot,SynCommons,Contnrs;
type TItem = class(TObject)
private
fItemName: RawUTF8;
fItemCode: Integer;
published
property ItemName : RawUTF8 read fItemName write fItemName;
property ItemCode : Integer read fItemCode write fItemCode;
end;
type TSQLNested = class(TSQLRecord)
private
fName: RawUTF8;
fItems: TObjectList;
public
constructor Create;
protected
destructor Destroy;override;
published
property Name : RawUTF8 read fName write fName;
property Items : TObjectList read fItems write fItems;
end;
function CreateDataModel: TSQLModel;
implementation
function CreateDataModel: TSQLModel;
begin
result := TSQLModel.Create([TSQLNested]);
TJSONSerializer.RegisterClassForJSON(TItem);
end;
But I still get error:
Unhandled stfUnknown/tkClass type for property Items.
Seems unrelated to TItem and it does not like the TObjectList. Also tried with Generics.Collections version.
Last edited by AntonE (2014-07-30 11:53:03)
Offline
Sounds like if there was indeed a problem.
Now TObjectList published properties will be recognized as sftObject kind.
See http://synopse.info/fossil/info/b5724a6c644d8
Offline
Thank you very much, it's working one level deep.
Test project here:
ftp://ftp.true.co.za/TestORM.zip
If compiled as-is it works, compile with conditional directive TWOLEVELS to make another TObjectList within a TObject class and it fails to persist even first level.
JSONvalues looks right when updating but I'm a bit lost 'deeper inside' mORMot yet.
This can be very powerful.
Offline
I figured my problem out.
Subitem that have properties that need init code, like TObjectList only have e.g. TObject.Create called and it's not virtual.
If I descend from TSQLRecord instead of TObject (even not register it to Model), then I can make
Constructor Create;override;
and it therefore works perfectly multiple-levels deep.
Regards
Last edited by AntonE (2014-07-31 23:36:21)
Offline
Or you can just use TPersistentWithCustomCreate instead of TSQLRecord.
It may be less confusing, since your nested class are not part of the ORM (nor defined in the data model), but just value objects.
Offline