Delphi Databases: Dynamic Datamodules at Runtime
by Charles E. Weindorf
Delphi Consultant 
Charles.Weindorf@mudsox.com

One farmer's adage states "Don't try to put 10 pounds of potatoes in a five pound sack." Although this would seem to be common sense, I was in the middle of a Delphi project that attempted to get to the 10 pound limit and beyond. The visual programmers of the team needed access to over 70 database tables on a multitude of different forms. One master datamodule became the traffic cop for all 70 tables as well as business logic that manipulated the data. Since any one form would use 2-20 tables, there were many instances of queries and datasources (at least 5 pounds worth) that were not being used in the datamodule. However, if we tried to break this big datamodule into smaller datamodules, we found that some forms required very diverse combinations of tables. Maintenance of the multiple datamodules would become a problem, while some of the forms continued to require multiple datamodules. With a good deal of experimentation, I have tried a variety of techniques to strike a balance between a central datamodule that is easy to maintain but trim at runtime. The following methods describe the evolution of housing queries and datasources within Delphi projects.
Method 1: TQuery/TDataSource on all Forms
This is the good-old method that has been with us since Delphi 1. What could be easier than placing a query on the form and linking field to a local datasource? Although this is RAD 101, it causes problems in maintaining the database. Since the many forms in a large project, a query many be needed in any places. Any changes to a table may need to be made on many forms. In addition, the business logic that accompanies the query is duplicated as well. In Delphi 2, a major advance was...
Method 2: Components in Datamodule
The datamodule is a convenient place to keep all queries and datasources. In addition, any of the business code that manipulates the database could be centralized as well. The problem with using a single instance of a datamodule is managing multiple forms. As focus shifts between forms that share the links of a database, the datamodule needs to focus on the correct records to support those forms. Although the single instance copy of the datamodule saves memory and resources, a programmer must build routines to keep the right data one the right form.
Method 3: Many Instances of  Datamodule
In order to keep the synchronization between a form and datamodule, each form could have its own instance of the complete datamodule. This may be the least efficient way to use runtime resources. Like Method 1, the table business logic is duplicated within each instance. In addition, there will be datasources and queries that are unused on the datamodule. Like Method 2, database maintenance is simplified because the logic is centralized.
Method 4: The Dynamic Datamodule
The dynamic datamodule's goals:
Allow each form instance to have a matching datamodule
Tailor a datamodule to match the dataset needs of the form.
Break all business logic out of both the form and datamodule.
Show me the code!
As those Linux folks know, a great way to learn and build new features in your systems is to use the open source. To see the dynamic datamodule technique described in Method 4, help yourself to the example code available through the link below. This code is offered without copyright and you may wish to use it as a framework for your own tests. I would really like any feedback that you can give: please contact Chuck Weindorf at Charles.Weindorf@mudsox.com
How a Dynamic Datamodule works: The datamodule is very thin - the queries and datasources are declared as public variables. When a form is created, an instance of dtmDynamicDatamod is also created. The main menu calls pmDatamoduleManager with the instance of the new form. pmDatamoduleManager scans through the form visual component list and checks the tag field for datalinked fields like tdbedit, tdbgrid, etc. Each tag matches a specific query and datasource combination.
101 in TAG field DD_Entity - Master search index for Customer
102 in TAG field DD_Address - Addresses for customers
103 in TAG field DD_Financial - Customer financial information
104 in TAG field DD_Order - Orders for customer
105 in TAG field DD_Items - Items within each order

prmDatamoduleManager creates the query and datasource and links the field to the correct component. The result is a datamodule that will automatically adjust as the programmer adds visual components. For example, to pull a field from a new table, the programmer would add a tdbedit component with the field name and the correct tag number. At runtime pmDataModule manager detects the new tag number and creates an instance of the correct query/datasource.

To download the complete project click here.

UNITS in DynamDatamodule  
DynamDatamodule Main project to set alias and create MainMenu - see comments in unit
frmMainMenu Main menu shows the list of clients and creates Client, Financial and Order
frmClient Client form that uses the client and address tables
frmFinancial Financial form that uses the client and financial tables
frmOrder Order form that uses the client, financial and order tables
dtmDynamicDatamod The blank datamodule with no design-time components - built dynamically
prmDatamoduleManager Compares the form being created with the tag list to create datasources
prmBusinessCode Contains code that will manipulate all instances of Client, Financial and Order

I have it. What do I do with it?
The project code has been tested in both Delphi 3 and Delphi 5. Unzip the source code to a directory of your choice and use your compiler to build the executable. Run the project and use the 3 toolbar buttons to display the Customer, Financial and Order forms. Notice that you can bring up as many instances as you wish, and each one will interact with its own datamodule.

Hit Counter