#1 2011-03-23 12:46:12

coblongpamor
Member
From: Bali-Indonesia
Registered: 2010-11-07
Posts: 130
Website

Recursif Record Reference

How to implement a Recursif Record Reference in the same table?

is Record Class Defininition like bellow correct?

TSQLAccount= class(TSQLRecord)
private
  fAccountNumber: TRawUTF8;
  fAccountName: TRawUTF8;
  fAccountLevel: Integer;
  ...
  ...
  fHeaderAccount: TSQLAccount;
published
  ...
  HeaderAccount: TSQLAccount read fHeaderAccount write fHeaderAccount;
  AccountLevel: Integer read fAccountLevel write fAccountLevel;
  ...
end;

so i can do something like this

var
  aAccount:TSQLAccount;
  aHeaderAccount:TSQLAccount;
begin
  ...
  ...
  aHeaderAccount:=aAccount.HeaderAccount;
  aAccount.Level:=aHeaderAccount.Level+1;
  ...
  ...
end;

thanks.

Offline

#2 2011-03-23 12:52:24

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

Re: Recursif Record Reference

The published properties of TSQLRecord children are not class instances, but a pointer(ID) or TObject(ID).
(the only exception is the TSQLRecordMany properties, which are automatic created instances of pivot tables)

So aHeaderAccount.Level+1 (or aAccount.HeaderAccount.Level+1) won't work.
It will raise a GPF.

aAccount.HeaderAccount is not a TSQLAccount class instance, but TSQLAccount(HeaderAccountID).
You'll have to typecast it to integer(aAccount.HeaderAccount) or even better to PtrInt(aAccount.HeaderAccount) in order to retrieve the record ID, then ask the database for the record content, or just one field value in your case.
There is also the ID property which could be used to make this typecast: the GetID method will detect that self is not a class instance, but a record ID, and return ID.

You'll have to use something like that:

  aAccount.Level := GetInteger(Client.OneFieldValue(TSQLAccount,'Level',PtrInt(aAccount.HeaderAccount)));

or even more easy to read:

  aAccount.Level := GetInteger(Client.OneFieldValue(TSQLAccount,'Level',aAccount.HeaderAccount.ID));

Or even retrieve the associated Header account:

aHeaderAccount := TSQLAccount.Create(Client,aAccount.HeaderAccount.ID));

 
I've just added a new constructor:

    {{ this constructor initializes the object and fill its content from a client
      or server connection, from a TSQLRecord published property content
     - is just a wrapper around Create(aClient,PtrInt(aPublishedRecord))
       or Create(aClient,aPublishedRecord.ID)
     - a published TSQLRecord property is not a class instance, but a typecast to
       TObject(RecordID) - you can also use its ID property
     - if ForUpdate is true, the REST method is LOCK and not GET: it tries to lock
      the corresponding record, then retrieve its content; caller has to call
      UnLock() method after Value usage, to release the record }
    constructor Create(aClient: TSQLRest; aPublishedRecord: TSQLRecord;
      ForUpdate: boolean=false); overload;

which will allow to write such code:

aHeaderAccount := TSQLAccount.Create(Client,aAccount.HeaderAccount));

Another way of getting the aHeaderAccount class instance is perhaps:

aHeaderAccount := TSQLAccount.Create;
  (...)
Client.Retrieve(aAccount.HeaderAccount.ID,aHeaderAccount);

Offline

Board footer

Powered by FluxBB