TDatabaseManager.Create() and Rtti problem

TDatabaseManager.Create() and Rtti problem

Try this.
Create an entity
 

unit uEntity;

interface

uses Aurelius.Mapping.Attributes;

type

  [Entity]
  [Table('DEPARTMENT')]
  [Sequence('SEQ_DEPARTMENT')]
  [Id('FId', TIdGenerator.IdentityOrSequence)]
  TDepartment = class
  private
    [Column('ID', [TColumnProp.Unique, TColumnProp.Required, TColumnProp.NoUpdate])]
    FId: Integer;
    [Column('DEPARTMENT_NAME', [TColumnProp.Required], 50)]
    FDepartment_Name: string;
  public
    property Id: Integer read FId write FId;
    property Department_Name: string read FDepartment_Name write FDepartment_Name;
  end;


implementation

end.


and create a  Delphi form only dedicated to build the database objects:


procedure TfrmMappedClasses.actCreateExecute(Sender: TObject);
var
  DBManager: TDatabaseManager;
  sMsg: string;
begin
  DBManager := TDatabaseManager.Create(GetDBConnection);
  try
    DBManager.BuildDatabase;
    DBManager.Free;
  except
    on E: Exception do
    begin
      DBManager.Free;
      MessageDlg(E.Message, mtError, [mbOK], 0);
      exit;
    end;
  end;
end;


where:
    - actCreate action is called from a button;
    - GetDBConnection method creates the IDbConnection instance.
IMPORTANT:
    uEntity exists in the uses clause of the form;
    the private and public sections of TfrmMappedClasses class declaration must not contain members of type TDepartment.

When actCreate action is executed, nothing happens (table DEPARTMENT and sequence SEQ_DEPARTMENT are not created).
When you add an useless
    department: TDepartment
member to the private or public section of class TfrmMappedClasses, the database objects are created.


If you inspect Aurelius (version 1.4) Aurelius.Mapping.MappedClasses unit, you notice that gathering Entity classes is achieved through an Rtti context:

procedure TMappedClasses.GetEntityClasses(AList: TList<TClass>);
var
  Context: TRttiContext;
  AllTypes: TArray<TRttiType>;
  T: TRttiType;
  A: TCustomAttribute;
begin
  Context := TRttiContext.Create;
  try
    AllTypes := Context.GetTypes;
    for T in AllTypes do
      if T.IsInstance then
        for A in T.GetAttributes do
          if A is Entity then
            AList.Add(T.AsInstance.MetaclassType);
  finally
    Context.Free;
  end;
end;

We can debug this code with CodeSite:

...
  try
    AllTypes := Context.GetTypes;
    {$IFDEF CODESITE}
    for T in AllTypes do
    begin
      CodeSite.Send(T.Name);
    end;
    {$ENDIF}
    for T in AllTypes do
...

It appears that Context.GetTypes contains TDepartment if and only if class TfrmMappedClasses (the form class) has a TDepartment member (private or public).

How to solve this problem?

    

That is because the linker removes any classes that are not a feild in another object or instantiated.
Either: Create an instance of each mapped object OR descend your objects from TPersistent rather than Tobject and use the RegisterClasses() call in an initialization section to tell the RTTI about each class - now Aurelius can find them and will build the correct database for you.