TDatabaseManager.Create() and Rtti problem - (2) a suggestion
It looks like Rtti only knows types when instances of this types appear explicitly in the code.
In order to force Rtti to "discover" entities, here is my proposition:
* declare somewhere in Aurelius code - in interface section of Aurelius.Mapping.MappedClasses, for example - a procedure called RegisterEntity(clazz: TClass).
* implement this procedure with an empty body (it does nothing special):
procedure RegisterEntity(Clazz: TClass);
begin
end;
* in the delphi unit implementing the entities,
- add Aurelius.Mapping.MappedClasses to the uses clause;
- create an initialization section at the end of the unit containing:
initialization
RegisterEntity(<entity class name>);
Of course, better solutions are welcome.
Registering an entity is only needed when the program never makes use of instances of this entity (for example, when the only purpose of the software is to build a database schema).
************************* Current message follows this one:
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?
Hi Etienne,
Hi,
I encountered a similar problem.
I have source like this
try
DM := TDatabaseManager.Create(Connection);
DM.BuildDatabase;
finally
DM.Free;
end;
OM := TObjectManager.Create(Connection);
try
P := TPersonal.Create;
P.Free;
finally
OM.Free;
end;
and some entity classes in uses. If I remove the second block of code (where TObjectManager), creating a db schema does not occur (as if I have no entity classes). I spent three nights to find it. This is a bug or something else?
(p.s. sorry for my english)
That's exactly the same "problem". If TPersonal class is not used in your application, linker removes it and Aurelius cannot know about it. You must keep the code, or just write a line like this:
Wagner, thanks for the answer. It was the only bad moment. Otherwise I am very pleased with the Aurelius and i'm waiting for 'schema update' feature :)
Simpler solution:
Base your object classes on TPersistent rather than TObject. Then in an initialization section, use the normal RegisterClasses({...]) call.
I am using this approach to build a simple tool to compare database structure with Aurelius model allowing updating / rejectinbg a malformed database.