#1 2023-10-28 18:12:05

dcoun
Member
From: Crete, Greece
Registered: 2020-02-18
Posts: 430

is it possible to map ID of a TOrm to a Record variable?

Let me explain better the question

Here is a TOrm derived definition:

type
  Dmyclass=record myid:TID; othervar:PtrInt; end;

  TOrmMyclass=Class(TOrm)
    private
      function GetfID: TID;            
      procedure SetfID(const Value: TID);
    public
      myclassdata:Dmyclass;
      class function createxml(_pat: TOrmapipatient; author:ixmldocument; const visdata:Dapidocvisit):rawutf8;
      class procedure InitializeTable(const Server: IRestOrmServer; const FieldName: RawUtf8; Options: TOrmInitializeTableOptions); override;
      property IDValue: TID read GetfID write SetfID;
      property ID: TID read GetID write SetfID;
    published
      property othervar: PtrInt read myclassdata.othervar write myclassdata.othervar;
  end;

function TOrmMyclass.GetfID: TID;
begin 
  result:=myclassdata.myid; 
end;

procedure TOrmMyclass.SetfID(const Value: TID);
begin 
  fID:=Value; 
  myclassdata.myid:=value; 
end;

I am using this record to be able to copy data from one TOrmMyclass instance to an other by just copying the myclassdata record variable between them.
The problem is that if am using TOrmMyclass.FillFrom to fill TOrmMyclass's instance data from JSON, the ID is filled correctly but not the myclassdata.myid
Can this be possible? Should I change something in the Rtti for that, and how?
Thank you in advance

Offline

#2 2023-10-28 22:12:33

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

Re: is it possible to map ID of a TOrm to a Record variable?

dcoun wrote:

I am using this record to be able to copy data from one TOrmMyclass instance to an other by just copying the myclassdata record variable between them.

Why do you want to do it this way? Does not the following also meet your requirements:

type
  TOrmItem = class(TOrm)
  private
    FField1: Integer;
    FField2: Integer;
    FField3: Integer;
  published
    property Field1: Integer
      read FField1 write FField1;
    property Field2: Integer
      read FField2 write FField2;
    property Field3: Integer
      read FField3 write FField3;
  end;

var
  item1, item2: TOrmItem;
begin
  item1 := TOrmItem.CreateWithID(High(Int64));
  try
    item1.Field1 := 1;
    item1.Field2 := 2;
    item1.Field3 := 3;
    var json: RawJson := item1.GetJsonValues({Expand=} False, {WithID=} True, 'Field1,Field3');
    item2 := TOrmItem.CreateWithID(1);
    try
      ShowMessage(item2.GetJsonValues(True, True, ALL_FIELDS));
      item2.FillFrom(Pointer(json));
      ShowMessage(item2.GetJsonValues(True, True, ALL_FIELDS));
    finally
      item2.Free;
    end;
  finally
    item1.Free;
  end;

The result is:

{"RowID":1,"Field1":0,"Field2":0,"Field3":0}
{"RowID":9223372036854775807,"Field1":1,"Field2":0,"Field3":3}

With best regards
Thomas

Offline

#3 2023-10-29 06:28:02

dcoun
Member
From: Crete, Greece
Registered: 2020-02-18
Posts: 430

Re: is it possible to map ID of a TOrm to a Record variable?

tbo wrote:

Why do you want to do it this way? Does not the following also meet your requirements:

I am already using this way, too. But copying a record is much more fast and you can pass it also as a pointer if needed (in a Torm with multiple records)

Offline

#4 2023-10-29 06:57:02

igors233
Member
Registered: 2012-09-10
Posts: 241

Re: is it possible to map ID of a TOrm to a Record variable?

AFAIK only published variables will be serialezed, your record is public variable.

Do note that you can use TDocVariantData instead of record, it's much more powerful and sometimes equally fast since it's stored as Variant and that can also be copied by reference.

Last edited by igors233 (2023-10-29 06:57:34)

Offline

#5 2023-10-29 07:02:14

dcoun
Member
From: Crete, Greece
Registered: 2020-02-18
Posts: 430

Re: is it possible to map ID of a TOrm to a Record variable?

igors233 wrote:

AFAIK only published variables will be serialezed, your record is public variable.

Do note that you can use TDocVariantData instead of record, it's much more powerful and sometimes equally fast since it's stored as Variant and that can also be copied by reference.

My record's selected members can be also published properties and being serialized from TOrm (as happens with "othervar" in the above example). TDocVariantData has the same problem with the TOrmMyclass's ID, so the question is the same for it too.

Offline

#6 2023-10-29 09:23:18

igors233
Member
Registered: 2012-09-10
Posts: 241

Re: is it possible to map ID of a TOrm to a Record variable?

I'm not sure then where serialization fails, is it when you have a property that writes to a record member or when you have a property that is a record?

Seems you want to have a published properties that are members of record in order to easier exchange those records, that's deinitely non standard behaviour, so it may work or not.
I would suggest to simplify design, define your orm object with fields it needs and have, use simple types for fields, (string, integer) and Variant (json object) where more complex data is required or when you need to exchange data among few classes.

Offline

#7 2023-10-29 10:53:00

dcoun
Member
From: Crete, Greece
Registered: 2020-02-18
Posts: 430

Re: is it possible to map ID of a TOrm to a Record variable?

igors233 wrote:

I'm not sure then where serialization fails, is it when you have a property that writes to a record member or when you have a property that is a record?

Seems you want to have a published properties that are members of record in order to easier exchange those records, that's deinitely non standard behaviour, so it may work or not.
I would suggest to simplify design, define your orm object with fields it needs and have, use simple types for fields, (string, integer) and Variant (json object) where more complex data is required or when you need to exchange data among few classes.

Published properties even when their content is read/written to record members, works like a charm
My problem and my question is about TOrmMyclass's ID that it is double saved to fID and myclassdata.myid
During unserialization with FillFrom and other routines, the SetfID is not used.
I am wondering if a Rtti custom method is used for setting fID and how to change it to use my SetfID procedure

Offline

#8 2023-10-30 07:22:49

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

Re: is it possible to map ID of a TOrm to a Record variable?

@dcount
You are defining your own ID property.
The problem is that it is a very special property for TOrm, which is handled specifically by the ORM core.
For compatibility reasons with mORMot 1, it is not even published, and it has the IDValue for direct access and
Using TOrm.fID is hardcoded into the framework core, and can't be overridden.

So the answer to your question is "no, it is not possible to map a TOrm.ID to a record".

Anyway, changing as such the behavior of a parent class in a child class is not a safe approach.
It breaks the SOLID principle, especially the Liskov substitution principle.

Why not go the other way round, and define your record - and not ID: TID as a property with a getter/setter functions?
It is always possible to map a record variable from any other fields, including IDs.
That is what I would have done, if I understand correctly your needs.

Offline

#9 2023-10-30 07:55:36

dcoun
Member
From: Crete, Greece
Registered: 2020-02-18
Posts: 430

Re: is it possible to map ID of a TOrm to a Record variable?

Thank you ab , I have seen  the special handle from the source and that is the reason for my question.
The last paragraph, is something I do not know in pascal: How can I map a record variable like myclassdata.myid to fID in Tormmyclass?
Thank you again

Offline

#10 2023-10-30 08:07:08

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

Re: is it possible to map ID of a TOrm to a Record variable?

If I understand correctly, your use case is:

I am using this record to be able to copy data from one TOrmMyclass instance to an other by just copying the myclassdata record variable between them.

Just define some methods using this record as parameter, to pass the value.

Something like:

procedure TOrmMyclass.FromData(const myclassdata: Dmyclass);
begin 
  fID := myclassdata.myid; 
  fOtherVar := myclassdata.othervar;
end;

procedure TOrmMyclass.ToData(out myclassdata: Dmyclass);
begin 
  myclassdata.myid := fID; 
  myclassdata.othervar := fOtherVar;
end;

Offline

Board footer

Powered by FluxBB