#1 2023-05-23 19:21:00

mdoyle
Member
Registered: 2020-11-29
Posts: 25

Using TCollection inTOrm

In mORMot1 I used to use TCollection a lot as described in the documentation in 5.5.2.1.2.3. TPersistent/TCollection fields. This also worked in mORMot2 until commit 88742d0 several ORM raw optimizations.

As far as I can see the create constructor was changed to InternalCreate which does not call the overloaded Create constructor anymore.
So the TCollection is not created anymore, is null and can't be set when getting data from the database.

constructor TSQLRecordPeopleObject.Create;
begin
  inherited;
  fPersistent := TCollTst.Create;
  fUTF8 := TRawUTF8List.Create;
end;

Please find a test example in https://gist.github.com/martin-doyle/a4 … 18facfad6c.

Is TCollection still supported and what is the recommended way of using it?

Offline

#2 2023-05-24 13:52:36

tbo
Member
Registered: 2015-04-20
Posts: 353

Re: Using TCollection inTOrm

mdoyle wrote:

Is TCollection still supported and what is the recommended way of using it?

You are right, now you have to write the following:

procedure TTestData.TestRetreiveOrmWithCollection;
...
  TestClient := TRestClientDB.Create(FModel, nil, DataFile, TRestServerDB, false, '');
  try
    Order := TOrmOrderBook.Create;
    try
      if Order.FillPrepare(TestClient.Orm, '', []) then
      begin

The documentation is also not entirely clear at this point. Let's see what Arnaud says when he gets back.

With best regards
Thomas

Offline

#3 2023-05-24 17:05:37

mdoyle
Member
Registered: 2020-11-29
Posts: 25

Re: Using TCollection inTOrm

Thanks Thomas, that keeps me working.
I was only able finding the right commit and spot. This fix helps a lot.

Offline

#4 2023-05-28 07:01:57

mdoyle
Member
Registered: 2020-11-29
Posts: 25

Re: Using TCollection inTOrm

The same happens when using one of the Create functions with paramters.

Order := TOrmOrderBook.Create(TestClient.Orm, 'OrderNo = ?', ['Order1']);

The work around is currently using the Retrieve function like

Order := TOrmOrderBook.Create;
  try
    TestClient.Orm.Retrieve('OrderNo = ?', [], ['Order1'], Order); 

I updated the tests in https://gist.github.com/martin-doyle/6c … a26990e46e.

By the way, I like the idea of embedding detail data within the record (sharding). Would be interesting to know what other people use, just schemaless TDocVariant?

Offline

#5 2023-05-28 11:11:53

AOG
Member
Registered: 2014-02-24
Posts: 490

Re: Using TCollection inTOrm

By the way, I like the idea of embedding detail data within the record (sharding). Would be interesting to know what other people use, just schemaless TDocVariant?

I mostly (always) use sharding, together with json storage. Keeps the raw database data in a format that also can be read by other applications not based on the mORMot.

Offline

#6 2023-05-28 13:00:41

tbo
Member
Registered: 2015-04-20
Posts: 353

Re: Using TCollection inTOrm

mdoyle wrote:

By the way, I like the idea of embedding detail data within the record (sharding). Would be interesting to know what other people use, just schemaless TDocVariant?

I use it in conjunction with SOA and WebApps (TMcvApplication) when records are mostly just read, and can recommend it. This saves many JOINs when combining the data from different tables of the DB. As an example, you have events with presentations. In the overview are displayed: Date, topic, location, room, speaker, etc. Only the date comes from the schedule table. Everything else are foreign keys into other tables. Having an extra field here that contains all the data from other tables needed for display reduces the effort considerably and makes viewing fast. And because the data composition changes very rarely and everything is handled via SOA functions, it is practically no effort to maintain this field.

With best regards
Thomas

Offline

#7 2023-06-19 17:45:01

mdoyle
Member
Registered: 2020-11-29
Posts: 25

Re: Using TCollection inTOrm

mdoyle wrote:

In mORMot1 I used to use TCollection a lot as described in the documentation in 5.5.2.1.2.3. TPersistent/TCollection fields. This also worked in mORMot2 until commit 88742d0 several ORM raw optimizations.
As far as I can see the create constructors was changed to InternalCreate which does not call the overloaded Create constructor anymore.

Create with parameters and CreateAndFiilPrepare don’t work anymore. Any recommendations how to use TCollection and TPersistance from now on?

Please see the tests in https://gist.github.com/martin-doyle/6c … a26990e46e.

Offline

#8 2023-06-19 18:42:46

tbo
Member
Registered: 2015-04-20
Posts: 353

Re: Using TCollection inTOrm

mdoyle wrote:

Create with parameters and CreateAndFiilPrepare don’t work anymore. Any recommendations how to use TCollection and TPersistance from now on?

You make the same mistake again. If you do your own initializations in the constructor of an ORM object, you can NEVER take the overloaded constructors as long as Arnaud solved the problem with InternalCreate function. The overridden constructor is not called and thus the own variable classes are not initialized and all calls go to nothing. I think that this change of Arnaud was very unfortunate, but currently it is as it is. Change it as follows:

procedure TTestData.TestCreateAndFillPrepare;
...
  Order := TOrmOrderBook.Create;  // AndFillPrepare(TestClient.Orm, '', []);
  try
    Order.FillPrepare(TestClient.Orm, '', []);


procedure TTestData.TestCreate;
...
  Order := TOrmOrderBook.Create;  // (TestClient.Orm, 'OrderNo = ?', ['Order1']);
  try
    TestClient.Orm.Retrieve(FormatUtf8('OrderNo = ?', [], ['Order1']), Order);

I think if you want changes, you need to push Arnaud a little bit. wink

With best regards
Thomas

Last edited by tbo (2023-06-19 18:46:53)

Offline

#9 2023-06-20 12:39:31

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

Re: Using TCollection inTOrm

Please try https://github.com/synopse/mORMot2/commit/a056b7f9

You should now override InternalCreate instead of Create.

Offline

#10 2023-06-20 19:34:11

mdoyle
Member
Registered: 2020-11-29
Posts: 25

Re: Using TCollection inTOrm

Works perfectly.

TOrmOrderBook = class(TOrm)
…
public
  procedure InternalCreate;override;
procedure TOrmOrderBook.InternalCreate;
begin
  inherited InternalCreate;
  FItems := TItemCollection.Create(TItem);
end;

Thanks a lot.

Offline

Board footer

Powered by FluxBB