Master-detail relationships ADO and Delphi

sing two TTable or TQuery descendats to create master-detail database entry forms.

 Master-detail data relationships are a fact of life for every Delphi database developer; just as data relationships are a fundamental feature of relational databases.
In real time database programming, the data in one table is related to the data in other tables. In general, tables can be related in one of three different ways: one-to-one, one-to-many or many-to-many. This chapter will show you how to use one-to-many database relationships to deal effectively with the problem of joining two database tables to present information.
A one-to-many relationship, often referred to as a “master-detail” or “parent-child” relationship, is the most usual relationship between two tables in a database.
Common scenarios include customer/purchase data, patient/medical-record data, and student/course-result data. For example, each customer is associated with at least one order record. Valued customers have many order records involving significant sums and often a user needs to view one in connection with the other. In a one-to-many relationship, a record in Table A can have (none or one or) more than one matching record in Table B, but for every record in Table B there is exactly one record in Table A.
A typical master-detail data browsing form displays the results of a one-to-many relationship, where one DBGrid displays (or set of data enabled controls) the results of the first or master table. It then tracks a selection in the first DBGrid to filter the results of a second table used to display the details of the selection in the second DBGrid.
When working with the BDE and Delphi, the simplest way to assemble a master-detail form is to use the Database Form Wizard. Wizard simplifies the steps needed to create a tabular or data-entry form by use of an existing database, unfortunately it is designed to use the BDE versions of TTable and TQuery components. Everything the wizard does, we can do by hand.
Since, through this course, we are working with the ADOExpress set of Delphi components, we’ll need to set all the components step by step. Firstly we have to make sure that we have two tables in a master-detail relationship.

MS Access relationships
Our focus will be on the following two tables: Customers and Orders. Both tables are a part of the DBDEMOS database that comes with Delphi. Since both tables are Paradox tables, we’ll use the code from the previous article to port them to our working aboutdelphi.mdb MS Access database.
Notice that when you port those tables to Access both of them have no index or primary key nor are they linked in any way in Access.
The power in a relational database management system such as MS Access comes from its ability to quickly find and bring together information stored in separate tables. In order for MS Access to work most efficiently, each table in your database should include a field or set of fields that uniquely identifies each individual record stored in the table. If two tables are liked in a relation (of any kind) we should set that relation with the MS Access.

Customers-Orders relation
To set up the relationship, you add the field or fields that make up the primary key on the “one” side of the relationship to the table on the “many” side of the relationship. In our case, you would add the CustNo field from the Customers table to the Orders table, because one customer has many orders. Note that you have to set the CustNo in Customers to be the primary key for the table.

When creating a relation between two tables MS Access provides us with the Referential Integrity feature. This feature prevents adding records to a detail table for which there is no matching record in the master table. It will also cause the key fields in the detail table to be changed when the corresponding key fields in the master are changed – this is commonly referred to as a cascading update. The second options is to enable cascading deletes. This causes the deletion of all the related records in a detail table when the corresponding record in the master table gets deleted. These events occur automatically, requiring no intervention by a Delphi application using these tables.
Now, when we have all the relations set up, we simply link few data components to create a master-detail data browsing Delphi form.
Setting up Master/Detail with ADOExpress
Creating a master-detail data form is not to much complicated. Have an empty Delphi form, and just follow the steps:
1. Select the ADO page on the Component palette. Add two TADOTable components and one TADOConnection to a form.
2. Select the Data Access page on the Component palette. Add two TDataSource components to a form.
3. Select Data Controls page on the Component palette. Place two TDbGrid components on a form. Add two DBNavigator components, too.
4. Use the ADOConnection, the ConnectionString property, to link to the aboutdelphi.bdb MS Access database, as explained in the first chapter of this course.
5. Connect DBGrid1 with DataSource1, and DataSource1 with ADOTable1. This will be the master table. Connect DBNavigator1 with DataSource1.
6. Connect DBGrid2 with DataSource2, and DataSource2 with ADOTable2. This will be the detail table. Connect DBNavigator2 with DataSource2.
7. Set ADOTable1.TableName to point to the Customers table (master).
8. Set ADOTable2.TableName to point to the Orders table (detail).

If you, at this moment, set the Active property of both ADOTable components to true, you’ll notice that the entire Orders table is displayed – this is because we haven’t set up the master-detail relationship yet.

Your form should look something like:

Master-detail form at design time

MasterSource and MasterFields
The MasterSource and MasterFields properties of the TADOTable component define master-detail relationships in Delphi/ADO database applications.

Field Link DesignerTo create a master-detail relationships with Delphi, you simply need to set the detail table’s MasterSource property to the DataSource of the master table and its MasterFields property to the chosen key field in the master table.
In our case, first, set ADOTable2.MasterSource to be DataSource1. Second, activate the Field Link Designer window to set the MasterFields property: in the Detail Fields list box and the Master Fields list box select the CustNo field. Click Add and OK.
These properties keep both tables in synchronization, so as you move through the Customers table, the Orders table will only move to records which match the key field (CustNo) in the Customers table.
Each time you highlight a row and select a new customer, the second grid displays only the orders pertaining to that customer.
When you delete a record in a master table – all the corresponding record in the detail table are deleted. When you change a linked field in a record in a master table – the corresponding field in the detail table gets changed to (in as many records as needed).
Simple as that!
Stop. Note that creating a master-detail form with Delphi is not enough to support referential integrity features on two tables. Even though we can use methods described here to display two tables in a parent-child relation; if those two tables are not linked (one-to-many) within MS Access – cascading updates and deletes won’t take place if you try to delete or update the “master” record.

ADO Shaping
Shaped recordsets are an alternative to master-detail relationships. Beginning with ADO 2.0, this method is available. Shaped recordsets allow the developer to retrieve data in a hierarchical fashion. The shaped recordset adds a special “field” that is actually a recordset unto itself. Essentially, data shaping gives you the ability to build hierarchical recordsets. For instance, a typical hierarchical recordset might consist of a parent recordset with several fields, one of which might be another recordset.
For an example of the SHAPE command take a look at the shapedemo project that shiped with Delphi (in the DemosAdo directory). You must specify the shaping provider in your connection string, by adding Provider=MSDataShape; to the beginning.

SHAPE {select * from customer}
APPEND ({select * from orders} AS Orders
RELATE CustNo TO CustNo)
Although it takes some time to master the SHAPE command that’s used to create these queries, it can result in significantly smaller resultsets. Data shaping reduces the amount of traffic crossing a network, provides more flexibility when using aggregate functions, and reduces overhead when interfacing with leading-edge tools like XML.