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.