Icon View Thread

The following is the text of the current message along with any replies.
Messages 1 to 10 of 11 total
Thread Dynamically creating EDB components on a datamodule
Wed, Oct 24 2012 2:39 AMPermanent Link

Peter

Hello

I have been in the habit of dropping an engine component, session and database onto my DataModules, but it is a problem when you have two datamodules open. I can use the Engine object that already exists, but I have to create an EDBDatabase and EDBSession component on the fly. I just declared a couple of components in the Public area of the DataModule...

 public
   { Public declarations }
   MyDatabase: TEDBDatabase;
   MySess      : TEDBSession;

then in the DataModule OnCreate method
....
MyDatabase  := TEDBDatabase.Create(Self);
MyDatabase.DatabaseName := 'BBTutorial';
MyDatabase.Database  := 'BBTutorial';
MySess := TEDBSession.Create(Self);
MySess.LoginUser := 'Administrator';
MySess.LoginPassword := '1234567';
MySess.AutoSessionName := True;
MySess.SessionType        := stLocal;
MySess.LocalConfigPath    := 'C:\Test2';
Engine.Name  := 'MyEDBEngine';
Engine.ConfigPath  := MySess.LocalConfigPath;
MyDatabase.SessionName := MySess.SessionName;

The MyDatabase and MySess components are visible and accessible from the other forms in the project, but I am concerned that it isn't sophisticated enough to survive an unanticipated error. The style above is of the dreaded Global Variable.

Should I write a GetMyDatabase method that returns a boolean if all went well? Similarly for the Session.

What do you people do?

Regards
Wed, Oct 24 2012 7:53 AMPermanent Link

Roy Lambert

NLH Associates

Team Elevate Team Elevate

Peter


>but I have to create an EDBDatabase and EDBSession component on the fly.

Why?

I just tested an approach - 3 datamodules. Drop engine on first one - add that to the interface uses clause for the other two modules, drop session / database components onto other datamodules and set up.

It all seems to work.


>Should I write a GetMyDatabase method that returns a boolean if all went well? Similarly for the Session.
>
>What do you people do?

I have a small function that creates and returns the object eg

function MakeEDBDatabase(const dbName: string; iSession: TEDBSession): TEDBDatabase;
begin
Result := TEDBDatabase.Create(nil);
Result.Database := dbName;
Result.DatabaseName := 'db-' + GUIDString;
Result.SessionName := iSession.SessionName;
end;

If you want to you can then test for nil, or raise an exception if things go wrong - they haven't for me so far.

Roy Lambert [Team Elevate]
Wed, Oct 24 2012 10:38 AMPermanent Link

David Cornelius

Cornelius Concepts

Avatar

It's never a problem to have more than one datamodule created.  A
datamodule is very similar to another form or unit in your project.  And
you don't really open a data module, you create and free it--it's an
object.

Concerning the database and session components, yes, they're public, but
only within the context of the data module, so if you free the data
module, the database and session are no longer available.  Therefore,
IMHO, it's fine as still fitting within a good object-oriented style.

You could write a GetMyDatabase method if that's your preference.  I
tend to just check the Active or Connected properties on the components
after I attempt to open them.

If you want to hide the details from outside units, for example if you
want to switch databases at a later time, then using custom properties
and methods will shield that dependency of knowing they are specifically
TEDB components and make the interface more generic. Many purists say
you should always do it this anyway--turn the data module into more of a
black box where only high-level methods are visible.

It really matters to you and the context of your application, who you
might be sharing your module with and the environment of your
development practices and/or team.

To handle unanticipated errors, put open attempts in a try/except block.

--
David Cornelius
Cornelius Concepts

On 10/23/12 23:39, Peter wrote:
> Hello
>
> I have been in the habit of dropping an engine component, session and database onto my DataModules, but it is a problem when you have two datamodules open. I can use the Engine object that already exists, but I have to create an EDBDatabase and EDBSession component on the fly. I just declared a couple of components in the Public area of the DataModule...
>
>    public
>      { Public declarations }
>      MyDatabase: TEDBDatabase;
>      MySess      : TEDBSession;
>
> then in the DataModule OnCreate method
> ...
>   MyDatabase  := TEDBDatabase.Create(Self);
>   MyDatabase.DatabaseName := 'BBTutorial';
>   MyDatabase.Database  := 'BBTutorial';
>   MySess := TEDBSession.Create(Self);
>   MySess.LoginUser := 'Administrator';
>   MySess.LoginPassword := '1234567';
>   MySess.AutoSessionName := True;
>   MySess.SessionType        := stLocal;
>   MySess.LocalConfigPath    := 'C:\Test2';
>   Engine.Name  := 'MyEDBEngine';
>   Engine.ConfigPath  := MySess.LocalConfigPath;
>   MyDatabase.SessionName := MySess.SessionName;
>
> The MyDatabase and MySess components are visible and accessible from the other forms in the project, but I am concerned that it isn't sophisticated enough to survive an unanticipated error. The style above is of the dreaded Global Variable.
>
> Should I write a GetMyDatabase method that returns a boolean if all went well? Similarly for the Session.
>
> What do you people do?
>
> Regards
>
Wed, Oct 24 2012 12:38 PMPermanent Link

Adam Brett

Orixa Systems

Peter,

I use the method Roy uses dressed up very slightly as a Singleton pattern ... which you may well already know. It is really a way of making Global variables which smell slightly less bad.

Using a singleton there is always only 1 DB connection in my applications & all / any data objects connect through it. I have a TMyDatabase descendent of TEDBDatabase which has a private method which creates the engine & session, so you don't have to worry about that happening & then returns an instance of itself.

The new version of Delphi includes the ability to generate Singleton objects very nicely, but if you own an older version it is usual to include an "Instance" method which returns a locally declared Const of the type of the singleton. You then need to add finalization code calling a method ReleaseInstance, which frees this const. Model Maker generates this pattern automatically on any class, if you own the Model Maker IDE extension just use this feature.

Adam
Wed, Oct 24 2012 1:34 PMPermanent Link

Roy Lambert

NLH Associates

Team Elevate Team Elevate

Adam


>Using a singleton there is always only 1 DB connection in my applications & all / any data objects connect through it. I have a TMyDatabase descendent of TEDBDatabase which has a private method which creates the engine & session, so you don't have to worry about that happening & then returns an instance of itself.

How does that work when you have both disk & memory based tables?

Roy
Wed, Oct 24 2012 8:48 PMPermanent Link

Peter

Roy asked why, and I should have said that the only time that it is a problem is when I open an another version of the same project, by dragging a different version of the pas file into the editor.

A couple of messages then warn that the database "MyDatabase" already exists.

So, Roy, how do you declare the new object, to make it visible to other forms in the project?

Adam said "The new version of Delphi includes the ability to generate Singleton objects very nicely". I have XE3 but I haven't explored the singleton subject. Where should I look? The Help is useless in this area - it only lists MS and C# material.

Regards

Peter
Thu, Oct 25 2012 4:00 AMPermanent Link

David Cornelius

Cornelius Concepts

Avatar

As far as the singleton goes, he might be referring to the new Spring
framework which only works in Delphi 2010 and up.  It has pretty simple
support for singleton objects.

The Spring framework will manage all your objects for you--you just ask
it for an object of a specific type when you need it and it gives it to
you.  So that way, they're "global" but also managed in a clean and
object-oriented way.

--
David Cornelius
Cornelius Concepts

On 10/24/12 17:48, Peter wrote:
> Roy asked why, and I should have said that the only time that it is a problem is when I open an another version of the same project, by dragging a different version of the pas file into the editor.
>
> A couple of messages then warn that the database "MyDatabase" already exists.
>
> So, Roy, how do you declare the new object, to make it visible to other forms in the project?
>
> Adam said "The new version of Delphi includes the ability to generate Singleton objects very nicely". I have XE3 but I haven't explored the singleton subject. Where should I look? The Help is useless in this area - it only lists MS and C# material.
>
> Regards
>
> Peter
>
Thu, Oct 25 2012 4:02 AMPermanent Link

Roy Lambert

NLH Associates

Team Elevate Team Elevate

Peter

>Roy asked why, and I should have said that the only time that it is a problem is when I open an another version of the same project, by dragging a different version of the pas file into the editor.

If you think that's bad try loading a second dm with the engine on it!

>So, Roy, how do you declare the new object, to make it visible to other forms in the project?

I generally use this approach in threads or discrete forms rather than generally through an app. If I did that I'd simply declare a global variable and assign the result to it.


Roy Lambert [Team Elevate]
Fri, Oct 26 2012 5:54 AMPermanent Link

Adam Brett

Orixa Systems

Roy

>>How does that work when you have both disk & memory based tables?

Aha ... it wouldn't. I only use disk-based tables, I actually have 2 singletons 1 for the local EDB Database (which I use for all application config settings, local user data etc.) & 1 for the CS/Cloud connection.

I have never tried working with memory based tables ... perhaps I should. I know they would be much faster, but I'm not sure of other reasons to use them.

Adam
Fri, Oct 26 2012 6:06 AMPermanent Link

Adam Brett

Orixa Systems

David & Peter,

Newer versions of Delphi (not sure when this started) support class properties.

TMyDB = class(TEDBDatabase)
 class var FMyDB:  TMyDB;
 class property Instance: TMyDB read FMyDB;
 class constructor create;
 class constructor destroy;

--

TMyDB.create
begin
 FMyDB:= TMyDB.Create;
 FMyDB.Databasename := ....; //add specific properties for this instance here.
end;

Then you can call TMyDB.Instance and return an instance of the class.

If you put the following in the ancestor of your query type:

TMyQuery.Create(aOwner: TComponent);
begin create(aOwner);
 Databasename:= TMyDB.Instance.Databasename;
.... //set other properties here.
end;

Every query you instantiate descending from this type will automatically connect to FMyDB.

So long as you include code in the finalization section of the unit where you declared FMyDB to free it when the app closes I believe it should all work. It does for me anyway.

Adam
Page 1 of 2Next Page »
Jump to Page:  1 2
Image