Create the TFDConnection in code (e.g. in the DM constructor).
Open the connection after the DM has been created.
For complex applications, I use a design where the application startup is divided into stages. The stage progression is centrally controlled and broadcast to all interested parties.
Something like this:
// The following could be in the .dpr file
type
TRunStageBoot = bsInit..bsReady;
TRunStageShutdown = bsShutdown..bsShutdown;
begin
// Broadcast startup progression
for var Stage := Low(TRunStageBoot) to High(TRunStageBoot) do
RunStageNotify(Stage);
Application.Run;
// Broadcast shutdown progression
for var Stage := Low(TRunStageShutdown) to High(TRunStageShutdown) do
RunStageNotify(Stage);
end.
...and the run stage management:
type
TRunStage = (
bsInit, // Whatever needs to run before the DMs are created. E.g. load config.
bsCreateModules, // Create DMs
bsConnectDatabase, // Connect to database
bsLoadDatabaseSchema, // Validate and update database schema
bsLogin, // Perform application login
bsInitUI, // Create main UI (e.g. mainform)
bsReady, // Show UI
bsShutdown // Application shutdown
);
IRunStageSubscriber = interface
{...GUID...}
procedure RunStageNotify(Stage: TRunStage);
end;
TRunStageDelegate = reference to procedure(Stage: TRunStage);
procedure RunStageNotify(Stage: TRunStage);
procedure RegisterRunStageHandler(Delegate: TRunStageDelegate); overload;
procedure RegisterRunStageHandler(const Subscriber: IRunStageSubscriber); overload;
// ...similar for unsubscribe...
implementation
var
// Create on demand in RegisterRunStageHandler. Free in finalization.
RunStageSubscribers: TList<IRunStageSubscriber>;
RunStageDelegates: TList<TRunStageDelegate>;
procedure RegisterRunStageHandler(Delegate: TRunStageDelegate);
begin
RunStageDelegates.Add(Delegate);
end;
procedure RegisterRunStageHandler(const Subscriber: IRunStageSubscriber);
begin
RunStageSubscribers.Add(Subscriber);
end;
procedure RunStageNotify(Stage: TRunStage);
begin
for var Subscriber in RunStageSubscribers do
Subscriber.RunStageNotify(Stage);
for var Delegate in RunStageDelegates do
Delegate(Stage);
end;
...
...and the DM with the connection would then look something like this:
type
TDataModuleDatabase = class(TDataModule, IRunStageSubscriber)
private
FConnection: TFDConnection;
private
// IRunStageSubscriber
procedure RunStageNotify(Stage: TRunStage);
public
constructor Create(AOwner: TComponent); override;
end;
var
DataModuleDatabase: TDataModuleDatabase;
implementation
constructor TDataModuleDatabase.Create(AOwner: TComponent);
begin
inherited;
FConnection := TFDConnection.Create(Self);
// Setup params on connection
...
// Register so we will be notified when the connection should be opened
RegisterRunStageHandler(Self);
end;
procedure TDataModuleDatabase.RunStageNotify(Stage: TRunStage);
begin
case Stage of
bsConnectDatabase:
FConnection.Open;
end;
end;
procedure RunStageNotify(Stage: TRunStage);
begin
case Stage of
bsCreateModules:
DataModuleDatabase := TDataModuleDatabase.Create(Application);
end;
end;
initialization
// Register so we will be notified when the DM should be created
RegisterRunStageHandler(RunStageNotify);
end;