Delphi Database Application Developers Book
Delphi Database Application Developers Book
Delphi Database Application Developers Book
Delphi enables you to create robust database applications quickly and easily. Delphi database applications can work directly with desktop databases like Paradox, dBASE, the Local InterBase Server, and ODBC data sources. The Delphi Client/Server edition also works with remote database servers such as Oracle, Sybase, Microsoft SQL Server, Informix, InterBase, and ODBC data sources. Delphi client applications can be scaled easily between mission critical network-based client/server databases, and local databases on a single machine. This chapter introduces Delphis database tools, including the Data Access and Data Controls component pages, the Fields Editor, the Database Desktop, and the Database Forms Expert.
You also need to have a working knowledge of the Database Management System (DBMS) your Delphi database applications access, whether it is a desktop database such as dBASE or Paradox, or an SQL server. For information specific to building client/server applications with Delphi, see Chapter 6, Building a client/server application. This book assumes you have a basic understanding of relational databases, database design, and data management. There are many third-party books covering these topics if you need to learn more about them.
Introduction
Delphi IDE
ReportSmith
Delphi Application
Report
SQL Links
dBASE Paradox InterBase for Windows ASCII
ODBC Drivers
ReportSmith Drivers
...
Table 1.1
Tool
ReportSmith Borland Database Engine (BDE) BDE Configuration Utility Local InterBase Server
These features enable you to build database applications with live connections to Paradox and dBASE tables, and the Local InterBase Server through the BDE. In many cases, you can create simple data access applications with these components and their properties without writing a line of code. The BDE is built into Delphi components so you can create database applications without needing to know anything about the BDE. The Delphi installation program installs drivers and sets up configuration for Paradox, dBASE, and the Local InterBase Server, so you can begin working with tables native to these systems immediately. The BDE Configuration Utility enables you to tailor database connections and manage database aliases. Advanced BDE features are available to programmers who need more functionality. These features include local SQL, which is a subset of the industry-standard SQL that enables you to issue SQL statements against Paradox and dBASE tables; low-level API function calls for direct engine access; and ODBC support for communication with other ODBC-compliant databases, such as Access and Btrieve. Delphi includes Borland ReportSmith, so you can embed database report creation, viewing, and printing capabilities in Delphi database applications. Delphi also includes the Database Desktop (DBD), a tool that enables you to create, index, and query desktop and SQL databases, and to copy data from one source to another. For more information about ReportSmith, see Creating Reports. For more information about the DBD, see Appendix A, Using Database Desktop. The Local InterBase Server is a single-user, multi-instance, 16-bit, ANSI SQL-compliant, Windows-based version of Borlands 32-bit InterBase SQL server that is available for Novell NetWare, Windows NT, and Unix. For more information, see the Local InterBase Server Users Guide. The following table lists the additional database features available in the Client/server edition of Delphi. These features extend Delphis database capabilities to access remote
Introduction
SQL database servers such as Sybase, Microsoft SQL Server, Oracle, Informix, and InterBase.
Table 1.2
Tool
SQL Drivers
SQL Links provide Delphi applications with SQL access to data residing on remote servers, including Sybase, Microsoft SQL Server, Oracle, and Informix. When an SQL Link driver is installed, SQL statements are passed directly to the server for parsing and execution. For more information about using passthrough SQL, see Chapter 5, Using SQL in applications.
What is a database?
Delphi programmers should understand some basic concepts about databases, data, and data access, before building database applications. A database consists of one or more tables, where each table contains a series of columns into which records (also called rows) are stored. Each record is identical in structure. For example, a database of addresses consists of a table with name, street address, city, state, and zipcode columns. The intersection of a single column and row is referred to as a field. Fields contain values. The following figure illustrates these concepts:
Figure 1.2 Structure of a table
Column names
CustNo
Current field
Name
Street
City
Current record
1221 Kauai Dive Shoppe 4-976 Sugarloaf Highway Kapaa Kauai 1231 Unisco 1251 Sight Diver PO Box Z-547 1 Neptune Lane Freeport Kato Paphos
Records
The current field is one field in a single record. The current record is a single record in a multi-record set that is the focus of attention. For example, some Delphi database applications display multiple columns and records in a grid format for editing. As far as Delphi controls are concerned, only one field in a single record is current, meaning that editing tasks affect only the data in that field. Different databases vary widely in structure. A database in Paradox consists of one or more files, each of which contains a single table or index, but an SQL relational database on a remote server generally consists of a single file that contains all tables, indices, and
other database structures. Delphis Data Access and Data Control components encapsulate the underlying structure of the databases your application uses, so that your application can present the same interface to an end user whether it accesses a local Paradox file or a database on a remote SQL server. The information in most databases is constantly changing. When you access a networked database from a Delphi application, many users may be accessing and updating the database at the same time. When any database application accesses a database, whether to process a query or generate a report, the application receives a snapshot of the database as it was at the time the application accessed the database. An applications view of data may differ from the data currently in the database, so database applications should always be robust enough to react to such data changes. For more information about building client/server applications that access remote data, see Chapter 6, Building a client/server application.
What is data?
In this book, data refers to information stored in a database. Data may be a single item in a field, a record that consists of a series of fields, or a set of records. Delphi applications can retrieve, add, modify, or delete data in a database.
Introduction
Data sources
Delphi database applications get their data through the BDE. The different data sources (not to be confused with the TDataSource component) that the BDE can use are shown in Table 1.3.
Table 1.3
Paradox dBASE ASCII files Local InterBase Server SQL Database Server: Oracle, Sybase, Microsoft SQL Server, Informix, InterBase ODBC data sources
Data source
File extension
.DB .DBF .TXT .GDB Depends on server
The following figure illustrates how Data Access and Data Control components relate to data, to one another, and to the user interface in a Delphi database application:
Figure 1.3 Database components architecture
Data Access Components Data Control Components TDBGrid TTable TDataSource TDBEdit TDBCheck Data TQuery TDataSource TDBGrid TDBEdit BDE TDBCheck (User Interface)
Delphi Form
As this figure illustrates, a form usually contains at least three database components: a dataset component (TTable and TQuery in the figure) that communicates with the BDE; a TDataSource component that acts as a conduit between a dataset component and the user interface; and one or more data control components, such as TDBEdit or TDBGrid, that enable a user to browse, edit, or enter data.
When building a database application, you place data access components on a form, then assign them properties that specify the database, table, and records to access. They provide the connection between a data source and Data Control components. At run time, after an application is built and compiled, data access objects are not visible, but are under the hood, where they manage data access.
Introduction
The following table lists the data access objects on the Data Access page, and briefly describes how they are used:
Table 1.4
TDataSource TTable
Component
TQuery
Four data access components deserve special mention. Most forms provide a link to a database with a TTable or TQuery component (or through a user-defined component based on the normally hidden abstract class, TDataSet, of which TTable and TQuery are descendents). Other forms provide a link to a database with TStoredProc, also a descendent of TDataSet. In turn, all forms must provide a TDataSource component to link a TTable, TQuery, or TStoredProc component to data control components that provide the visible user interface to the data. TTable, TQuery, (and TStoredProc, when it returns a result set) contain a collection of TField components. Each TField corresponds to a column or field in the table or query. TFields are created Automatically, when TTable, TQuery, or TStoredProc are activated. At design time, using the Fields editor. For more information about TFields and the Fields editor, see Chapter 3, Using data access components and tools. For more information about TStoredProc, see Chapter 6, Building a client/server application.
Understanding TTable
The TTable component is the easiest way for a programmer to specify a database table for access. To put a TTable component on a form:
1 Select the Data Access page from the Component palette. 2 Click the Table icon. 3 Click on the form to drop the TTable component. 4 Enter the directory where the database resides in the DatabaseName property of the Object Inspector window. For SQL databases, enter an alias name.
Note
An alias can also be used for local Paradox and dBASE tables. You can choose an alias from a drop-down list in the Object Inspector.
5 Enter the name of the table to use in the TableName property of the Object Inspector window, or you can also choose a table from the drop-down list instead of entering the name.
By default, a TTable component accesses every column in a table when you activate it. When a visual component, such as TDBEdit, is associated with a TTable object, it can display any field in the table. Multi-column visual components, such as TDBGrid, access and display columns in the table using the tables TField list. If you double-click a TTable component on a form, you invoke the Fields Editor. The Fields Editor enables you to control the way Data Control components display data. It can Create a static model of a tables columns, column order, and column type that does not change even if changes are made to the underlying physical table in the database. Provide convenient, readable, and efficient component names for programmatic access. Specify the order in which fields are displayed and which fields to include. Specify all display characteristics of fields. Add custom validation code. Create new fields for display, including calculated fields. For complete information about the Fields Editor, see Chapter 3, Using data access components and tools.
Understanding TQuery
The TQuery component provides a tool for data access using SQL statements, such as a SELECT statement, to specify a set of records and a subset of columns from a table. TQuery is useful for building local SQL queries against Paradox and dBASE data, and for building client/server applications that run against SQL servers. To put a TQuery component on a form:
1 Select the Data Access page from the Component palette. 2 Choose the Query icon. 3 Click on the form to drop the TQuery component. 4 Enter the directory where the database resides (or select an alias for SQL databases) in the DatabaseName property of the Object Inspector window. 5 Enter the SQL statement to use for data access in the SQL property of the Object Inspector window by clicking the list button to open the String Editor.
The Object Inspector window for TQuery does not contain a separate property for specifying a table name. Instead, a table name must always specified as part of the SQL statement in the SQL property.
Introduction
With Delphi Client/Server, you can right-click a TQuery component on a form, then select the Visual Query Builder from the pop-up menu. The Visual Query Builder enables you to connect to a database and build an SQL statement interactively. For complete information about the Visual Query Builder, see the online Help. If you double-click a TQuery component, you invoke the Fields Editor. The Fields Editor enables you to control the way Data Control components display data. For complete information on TQuery and the Fields Editor, see Chapter 3, Using data access components and tools.
Understanding TDataSource
Every dataset that supplies a data control component must have at least one TDataSource component. TDataSource acts as a bridge between one TTable, TQuery, or TStoredProc component and one or more data control components that provide a visible user interface to data. TTable and TQuery can establish connections to a database through the BDE, but they cannot display database information on a form. Data Control components provide the visible user interface to data, but are unaware of the structure of the table from which they receive (and to which they send) data. A TDataSource component bridges the gap. To put a TDataSource component on a form:
1 Select the Data Access page from the Component palette. 2 Choose the DataSource icon. 3 Click on the form to create the TDataSource component. 4 Enter the name of the TTable or TQuery component to use as a database connection source in the DataSet property of the Object Inspector. If the form contains any TTable or TQuery components, you can choose a component from the drop-down list instead.
Note
TDataSource is also used to link tables or queries in a master/detail form. For more information about master/detail forms, see Chapter 2, Building a sample database application: MASTAPP.
Many data controls are data-aware versions of component classes available on the Standard page of the Component palette. In addition to standard component functionality, data controls can display data from a field in a database table, or send new or modified data from a form to a database table.
10
The following table lists the data controls on the Data Control page.
Table 1.5 Data Controls components
Purpose
Data-aware navigation buttons that move a tables current record pointer forward or backward; start Insert or Edit mode; post new or modified records; cancel Edit mode; and refresh display to retrieve updated data. Data-aware label that can display a field from a currently active record. Data-aware edit box that can display or edit a field from a currently active record. Data-aware check box that can display or edit a Boolean data field from a currently active record. Data-aware list box that can display values from a column in a table. Data-aware combo box that can display or edit values from a column in a table. Data-aware radio group populated with radio buttons that can display or set column values. Data-aware custom grid that enables viewing and editing data in a tabular form similar to a spreadsheet; makes extensive use of TField properties (set in the Fields Editor) to determine a columns visibility, display format, ordering, etc. Data-aware memo box that can display or edit text BLOB data from a currently active record. Data-aware image box that can display, cut, or paste bitmapped BLOB images to and from a currently active record. Data-aware list box that displays values mapped through another table at run time. Data-aware combo box that displays values mapped through another table at run time.
Component
TDBNavigator
Data control components make up a consistent visual user interface for Delphi database applications, whether the application accesses a local database file, or a remote database server. To see how data control components are used in an application, see the subsequent chapters of this book. For a complete description of each data control component and its properties, see the online VCL Reference.
Introduction
11
Inexperienced database applications programmers can use the Database Forms Expert to learn how to build database forms. Experienced database applications programmers can use it to speed application development. To learn how to use the Database Forms Expert when building an application, see Chapter 2, Building a sample database application: MASTAPP.
12
Development scenarios
Since an applications design usually depends on the structure of the database it will access, the database must be defined before the application can be developed.
Note
Database development (also called data definition) is a part of the overall development process, but is beyond the scope of this manual. For more information, refer to the numerous books about relational database design. There are four possible scenarios for Delphi database application development: The database does not yet exist or must be re-defined. Use the Database Desktop utility to define Paradox and dBASE tables. For more information, see Appendix A, Using Database Desktop. For SQL servers, use the tools provided with the server or the Database Desktop. For example, for the Local InterBase Server or an InterBase Workgroup Server, use Windows ISQL. For more information, see the Local InterBase Server Users Guide and the InterBase Data Definition Guide. The database exists on a desktop or LAN data source (Paradox or dBASE) and the database will access it there. If the BDE and the data source are on the same machine as the application, then the application is a standalone (not client/server) application. The database exists on a desktop data source, and is being upsized to an SQL server. This scenario is discussed in Appendix C, Using local SQL. The database exists on an SQL server and the application will access it there. This is a standard client/server application. For information specific to developing a client/ server application, Chapter 6, Building a client/server application.
Introduction
13
There are database and application tasks in each of these phases. Depending on the size and scope of the development project, the database and application tasks may be performed by different individuals or by the same individual. Often, one team or individual will be responsible for the database tasks of the project, and another team or individual will be responsible for the application tasks.
Figure 1.6 Development cycle
Design
Development cycle
Implementation
Deployment
For client/server applications, the database and application tasks become more distinct, since they run on different platforms, often with different operating systems (for example, a Unix server and Windows 3.1 client). When development responsibilities are thus divided it is important to clearly delineate in the design phase which functions will be performed by the database server and which will be performed by the client application. Usually, the functional lines are clear cut. But database processes such as stored procedures can sometimes perform functions that can also be performed by the client application. Depending on the expected deployment configuration, application requirements, and other considerations, the design can allocate such functions to either client or server. It is also important to realize that database application development is by its nature an iterative process. Users may not fully understand their own needs, or may define additional needs as development proceeds. User interface elements are always refined as they are used. Also, changing business needs will change requirements over time. Generally, a number of iterations through the development cycle will be required before an application can meet a significant portion of its requirements.
Design phase
The design phase begins with requirements definition. In consultation with knowledgeable end users, define the functional specifications for the database and applications. Determine which aspects of the functional requirements will be implemented in the database design, and which aspects will be implemented in the applications. For client/server applications, often certain functions can be performed either by the server or by the application; for example, a complex mathematical transform function could be performed either by the client application or by a stored procedure on the server. The hardware deployment configuration will generally determine whether such
14
functions are best performed on the server or client. For example, if the client platforms are expected to be low-end desktop PCs, and the server platform is expected to be a high-end workstation, then it will probably be best to run computation-intensive functions on the server. If the hardware configuration changes, then it is possible to move the function between client and server in a later iteration.
Implementation phase
In the implementation phase, you use Delphi to build and test the application conceived in the design phase. During the implementation phase, you should use a duplicate data source, that is, a data source that has the same essential structure as the production database, but with a small subset of representative data. It is not recommended to develop an application against a production database, since the untested application may corrupt the data or otherwise interfere with normal database activities. If your application will ultimately be deployed to use a desktop data source, make copies of the required tables with the Database Desktop, and populate them with representative dummy data. If the application will ultimately be deployed to use a remote data source (an SQL server), then you can take two approaches during the implementation phase: Develop and test the application against a non-production database on the Local InterBase Server. Develop and test the application against a non-production database on the server. The first approach has the advantage that is isolated on the development platform(s), and so will not interfere with other server activities. It will not consume server resources or increase network traffic. Its primary disadvantage is that only standard SQL server features can be used and tested during this phase, if you are using a server other than InterBase for the deployed application. The second approach enables you to surface all server-specific features, but will consume network and server resources during testing. This approach can be dangerous, since it is conceivable that a programmer error could cause a server to crash during testing.
Deployment phase
In the deployment phase, the client/server application is put to the acid test: it is handed over to end users. To ensure that the applications basic functionality is error-free, deploy a prototype application before attempting to deploy a production application. Since the ultimate judges of an applications efficacy are its users, developers must be prepared to incorporate changes to applications arising from their suggestions, changing business needs, and for general enhancement (for example, for usability). Sometimes application changes may require changes to the database, and conversely, changes to the database may require application changes. For this reason, application developers and database developers should work together closely during this phase. As features and enhancements are incorporated into the application, the application moves iteratively closer to completion.
Introduction
15
Deploying a client/server application requires addressing a number of special issues, including connectivity and multiuser access. These issues are discussed in Chapter 6, Building a client/server application.
Deploying an application
Deploying an application means giving it to the end users, and providing the necessary software they need to use the application in a production environment. Non-database applications require only an .EXE file to runDelphi applications do not require a run time interpreter or DLL. Typically, when deploying a database application, you will create a package that includes all the files that end users need to run the application and access data sources. These files include The application .EXE file and .DLL files (if any) Required ancillary files (for example, a README file or .HLP files for online help) BDE support for database access (desktop or server) ReportSmith Runtime for running and printing reports If the application uses VBX controls, include each VBX along with BIVBX11.DLL
If you are distributing the files on disks, you will generally want to compress them with a standard file compression utility, and provide the utility on the disk. You may also want to build a simple installation application to install the files for your users. For complex applications, you may want to use one of the many commercially-available installation programs.
Important
Before distributing any files, ensure that you have the proper redistribution rights. As described in the Delphi license agreement, Delphi provides distribution rights for the BDE (including Paradox and dBASE support). Delphi Client/Server includes distribution rights for Borland SQL Links for Windows. Licenses for distribution of the Local InterBase Server are available from Borland. For information on deploying support for remote server access, see Chapter 6, Building a client/server application. For client/server applications, you also must ensure that the necessary communications software (for example, TCP/IP interface) is installed on the client platforms. This software is provided with databases servers. For more information, see your server documentation.
16
required to run your application, but you must still distribute all the files in the Redistributable BDE. For example, if your application needs access only to Paradox files, you can advise your users not to deploy the dBASE driver. The minimum BDE configuration for accessing a Paradox database requires about 500 Kbytes.
Note
For more information on deployment, refer to the file DEPLOY.TXT installed to the DELPHI\DOC directory by default.
Table 1.6
File name
IDAPI01.DLL IDBAT01.DLL IDQRY01.DLL IDASCI01.DLL IDPDX01.DLL IDDBAS01.DLL IDR10009.DLL ILD01.DLL IDODBC01.DLL ODBC.NEW ODBCINST.NEW TUTILITY.DLL BDECFG.EXE BDECFG.HLP IDAPI.CFG
Language drivers
The BDE provides the ability to localize applications with language drivers. The language driver DLL loads the drivers specified by Paradox or dBASE tables or in IDAPI.CFG for server databases. The language drivers are files with extension .LD installed to the LANGDRV sub-directory of the BDE directory.
Important
For language drivers to load correctly, the WIN.INI file must have the following entry, assuming the default installation directory:
[Borland Language Drivers] LDPath = C:\DELPHI\IDAPI\LANGDRV
Introduction
17
ODBC Socket
The BDE comes with an ODBC Socket. It has been certified with Microsofts 2.0 ODBC Driver Manager. If you have a different version of the ODBC Driver Manager: Back up your existing ODBC.DLL and ODBCINST.DLL Copy the version 2.0 files, ODBC.NEW and ODBCINST.NEW, from your BDE directory to your WINDOWS\SYSTEM directory. Rename these files to ODBC.DLL and ODBCINST.DLL.
Note
The ODBC 2.0 Driver Manager does work with ODBC 1.x ODBC drivers.
18
Chapter
Chapter 2
This chapter is a tutorial and introduction to building Delphi database applications. Examples show how to perform database tasks using Delphi interactively and by programming in Object Pascal. In each example you build a single form, self-contained and independent of the others. You can save yourself some work by doing the examples in sequence. Several examples use the same basic form as a starting point.
Note
This material assumes you know how to use Delphi; it tells you what to do to perform certain tasks. For more details (that is, to find out why), follow the cross-references in the For more information section that follows each example. In particular, see Chapter 3, Using data access components and tools. The tutorial consists of the following sections: Building forms describes how to use the Database Form Expert to create database forms, including single-table and master-detail forms. It also describes how to enhance forms by adding components and code by hand. Working with fields describes how to read and write field values, how to search for values and do table lookups, and how to format data displayed to the user. It also describes how to work with calculated fields. Using queries and ranges describes how to use SQL queries and set ranges to select a subset of the data in one or more tables. Printing reports and forms describes how to print ReportSmith reports and Delphi forms.
Building forms
The material in this section focuses on database issues. To learn about general application building with Delphi, see the Users Guide. The forms described here are the
19
basis for a database application called MASTAPP, designed to meet the record-keeping needs of the fictitious Marine Adventures & Sunken Treasures company (MAST). MAST sells diving equipment and arranges diving expeditions. MASTAPP tracks information about customers, orders, inventory, and vendors. The tutorial starts with a simple codeless form for viewing and editing table data, and works up to a full-featured invoice form containing several tables, data-aware components, and other advanced Delphi features. All the forms, tables, and related files are installed by default in C:\DELPHI\DEMOS\DB\MASTAPP. During a default installation of Delphi, an alias, DBDEMOS, that points to the MASTAPP directory is created for you, or you can create your own alias using the BDE configuration utility (see Appendix B). The following figure shows the forms and tells where they are described in this chapter:
Figure 2.1 Database forms described in the tutorial
Single table form, page 21. Master-detail form, page 24. One-many-many form, page 27.
Note
For general information about building Delphi forms, see the Users Guide.
MASTAPP aliases
All TTable and TQuery components used in example code in this chapter set their DatabaseName property to DBDEMOS. In contrast, the complete demo in the MASTAPP directory does the following to facilitate porting:
1 The main form (MAIN.PAS) has a TDatabase component with its AliasName property set to DBDEMOS and DatabaseName property set to MAST. 2 All datasets on all forms have their Database properties set to MAST. Now all forms can use a different BDE alias simply by changing the main forms TDatabase components AliasName property.
20
What to do
1 Choose Help|Database Form Expert to open the Form Expert. 2 Specify a table, fields, and field layout as shown in the following figure. The Form Expert creates the form. 3 Press F9 to run the form. Click the navigator control buttons to move through the records in the table.
Figure 2.2 Building a single-table form using the Database Form Expert
21
How it works
The Database Form Expert builds a single-table form to match your specifications, and adds a tool bar of navigation controls. The form shown in the following figure is the basis for the full-featured BRPARTS.DFM form in the MASTAPP application. The important relationships in a data-aware form like this one are the links between the underlying data, the nonvisual components, and the data controls that display data to the user.
Figure 2.3 A single-table form
TDBNavigator control linked to the table
The form contains one TTable component. The expert links it to the Parts table by setting the properties listed in the following table. A TTable component establishes a connection to a table in a database.
Table 2.1
Property
Active DataBaseName Name TableName
Remarks
When Active is False, data-aware controls do not display data at design time. To make controls display data at design time, set Active to True. MAST is an alias that points to where the table resides. Use aliases, not hard-coded paths, to make applications portable and easy to upsize. Use the Object Inspector to change names. Tells the component which table to link to.
The form contains one TDataSource component. The expert links it to the TTable component by setting the properties listed in the following table. A TDataSource component acts as a bridge between one dataset component (TTable in this case) and one or more data-aware controls that provide a visible interface to data.
Table 2.2
Property
AutoEdit
Remarks
When AutoEdit is True, Delphi puts the TDataSource into Edit state automatically when the user changes a value in a linked control. To make a TDataSource read-only, or to control when to enter Edit state, set AutoEdit to False.
22
Table 2.2
Property
DataSet Name
Remarks
Specifies which TTable (or TQuery) is supplying the data. Use the Object Inspector to change names.
The form contains one TDBGrid control. The expert links it to a TDataSource component by setting the properties listed in the following table. By default, a TDBGrid includes all the fields (columns) in a table. To limit the columns displayed by a TDBGrid, doubleclick on its associated TTable component to invoke the Fields Editor (see page 30).
Table 2.3
Property
DataSource
Remarks
Links the DBGrid control to a TDataSource component, which supplies the data.
The form contains one TDBNavigator control. This control moves a tables current record pointer forward or backward, starts Insert or Edit state, posts new or modified records, etc. The expert links this control to the Parts table by setting the properties listed in the following table.
Table 2.4
Property
DataSource VisibleButtons
Remarks
Links the control to a TDataSource component. For example, by default nbNext is True, so the Next Record button is visible; nbDelete is False, so the Delete button is invisible.
The expert does more than create a form and components. It also generates a line of code to open the table at run time in case you do not activate the table at design time. For example, the expert creates TTable components with the Active property set to False. Thats why the various TDBEdit controls arent displaying data. You could set Active to True, and the controls would display data from the first record. Instead, the Form Expert generates the following code to open the table at run time.
procedure TEditPartsForm.FormCreate(Sender: TObject); begin Table1.Open; end;
This code is hooked to the forms OnCreate event, so Delphi executes it before creating the form. As a result, the table is opened before the form is displayed.
Note
Code created by the Form Expert is like code you type yourself. If you rename components created by the expert, be sure to update your source file everywhere the renamed component occurs. Name changes to components that Delphi originates (for example, in the type declaration) are changed automatically for you by Delphi.
23
What to do
When you use the Database Form Expert, building a master-detail form is much like building a single-table form (for details, see page 21).
1 Choose Help|Database Form Expert to open the Form Expert. 2 In the first panel, specify a master-detail form that uses TTable objects. 3 In subsequent panels, specify the master table (CUSTOMER.DB), fields (use them all), and field layout (grid). 4 Specify the detail table (ORDERS.DB), fields (all), and field layout (grid). 5 Specify fields to link the master and detail tables as shown in the following figure, then tell the expert to create the form.
24
6 Press F9 to run the form. Click the navigator control buttons to move through the records in the table.
Figure 2.4 Linking fields in a master-detail form
1. Choose an index. All Paradox tables have a primary index by default. ORDERS.DB was also created to have a secondary index named ByCustNo that orders records by customer number. Choose ByCustNo from the combo box.
2. When you choose an index, Delphi updates the lists of possible linking fields. In each list, choose CustNo, then click Add.
3. When you click Add, Delphi shows how the fields are linked. Click Next to continue.
How it works
The expert builds a master-detail form much as it builds a single-table form (for details, see page 22). It creates TTable components and TDataSource components for the master table and the detail table and links them to the underlying data by setting properties. The expert creates controls to display the data from each table, and sets properties to link them to the corresponding TDataSource component. The expert also creates a TDBNavigator control linked to the master table.
25
Figure 2.5
A master-detail form
Detail TTable and TDataSource
TDBGrid control linked to master table TDBGrid control linked to detail table
What distinguishes a master-detail form is the link between the tables. For each record in the master table, the form displays all corresponding records in the detail table. Such a link is called a one-to-many relationship (see page 76 for more information). Delphi creates this relationship by setting properties of the TTable component linked to the detail table.
Table 2.5
Property
IndexFieldNames MasterFields MasterSource
The following table lists important properties for each component and control.
Table 2.6
TTable (master)
Component
Value
False MAST
Remarks
When Active is False, data from this table is not displayed. An alias that specifies where to find the table. Use aliases, not hard-coded paths, to make applications portable and easy to upsize. Use the Object Inspector to rename it (for example, Cust). Specifies the master table. Specifies which TTable is supplying the data to this component. Use the Object Inspector to rename it (for example, CustSource). Data from this table is not displayed at design time.
Name TableName
Table1 (by default). CUSTOMER.DB Table1 (by default) DataSource1 (by default) False
TDataSource (master)
DataSet Name
TTable (detail)
Active
26
Table 2.6
Component
Value
MAST
Remarks
An alias that specifies where to find the table. Use aliases, not hard-coded paths, to make applications portable and easy to upsize. Specifies a column to use to order records in the table. ByCustNo is a secondary index based on CustNo. You can also set the IndexFields property to ByCustNo. A list of one or more master table fields to link to. Use a semicolon to separate field names in the list. Identifies a TDataSource linked to the master table. Use the Object Inspector to rename it (for example, Orders). Specifies the detail table. Specifies which TTable is supplying the data to this component. Use the Object Inspector to rename it (for example, OrdersSource). Links the grid control to a TDataSource control. This data source provides a restricted view of the data in the Orders (detail) table, based on the values of the fields linked to the Customer (detail) table. The expert links the TDBNavigator control to the master table.
IndexFieldNames
CustNo
CustNo DataSource1 (by default) Table2 (by default) ORDERS.DB Table2 (by default) DataSource2 (by default) DataSource1 (by default) DataSource2 (by default)
TDataSource (detail)
DataSet Name
DataSource DataSource
DataSource
What to do
1 Choose Help|Database Form Expert to open the Form Expert. 2 In the first panel, specify a master-detail form that uses TTable objects.
27
3 In subsequent panels, specify the master table (CUSTOMER.DB), fields (use them all), and field layout (horizontal). 4 Specify the detail table (ORDERS.DB), fields (all), and field layout (horizontal). 5 Specify fields to link the master and detail tables: choose CustNo for the IndexFieldNames property and link the CustNo fields in each table. For details, see step 6 on page 25. 6 Tell the expert to create the form. 7 Move components around to make room at the bottom of the form. You may have to change the Align property of some controls from alClient to alNone. 8 Place a TTable component, a TDataSource component, and a TDBGrid component as shown in the following figure. (The TTable and TDataSource are on the Data Access components page; the TDBGrid is on the Data Controls page.) These components represent the third table in the one-many-many link. In this example its the Items table.
28
9 To create the link, set properties of these new components as shown in the following table.
Figure 2.6
TTable3, linked to ITEMS.DB
One-many-many form
TDataSource3, linked to TTable3
Table 2.7
TTable (third table)
Component
Value
True MAST
Remarks
False by default. Set Active to True after setting all other properties to display data in linked controls. An alias that specifies where to find the table. Use aliases, not hard-coded paths, to make an application portable and easier to upsize. Specifies a column to use to order records in the table. ByOrderNo is a secondary index based on OrderNo. You can also set the IndexFields property to ByOrderNo. A list of one or more master table fields to link to. Use a semicolon to separate field names in the list. Identifies a TDataSource component linked to the master table. Use the Object Inspector to rename it (for example, Items). The name of the third table in the link. Specifies which TTable is supplying the data to this component. Use the Object Inspector to rename it (for example, ItemsSource). This data source provides a restricted view of the data in the Items table, based on the values of the fields linked to the Orders table.
IndexFieldNames
OrderNo
OrderNo DataSource2 (by default) Table3 (by default). ITEMS.DB Table3 (by default) DataSource3 (by default) DataSource3 (by default)
DataSet Name
DataSource
29
How it works
A one-many-many form links data from three tables. The first table in the link (the Customer table) is the master table. The second table (Orders) does double duty: its the detail table for the first table and the master table for the third table. The third table (Items) is a detail table for the second table. In this example, you can link these tables quickly and easily by setting properties because secondary indexes were specified for the tables when they were created.
What to do
1 Use the Database Form Expert to build a single-table form that displays all the fields of CUSTOMER.DB in a grid. For detailed instructions, see page 21. 2 To make the grid display data at design time, use the Object Inspector to change the TTable components Active property to True.
30
3 Open the Fields Editor by double-clicking the TTable component. By default, the list of fields is empty, as shown in the following figure:
Figure 2.7 The Fields Editor
4 Click Add to open a dialog box listing the fields in the Customer table. By default, all fields are selected. Click CustNo to select it, then control-click to select the Company, Phone, and LastInvoiceDate fields, then click OK to confirm your choices and close the dialog box. In the form, the grid changes: instead of displaying all fields, it displays the only the fields you selected.
Figure 2.8 Adding fields to a data set
5 Use the Fields Editor to change the field order as follows: Click LastInvoiceDate in the list of fields, then drag it to the third place in the list, between Company and Phone. In the form, the grid changes to display columns in their new order. 6 Close the Fields Editor by choosing Close from the Control menu. 7 Press F9 to run the form. The grid displays the four fields in the order you specified.
How it works
This form is the basis for the full-featured CUSTORD.DFM form in the MASTAPP application. By choosing fields in the Fields Editor, you can tell a TTable component which fields to make available to the components that are linked to it. In effect, the Fields Editor changes the logical structure of the table. The Fields Editor also addsTField objects to the units type section (for example, CustCustNo: TFloatField;). More accurately, it adds a descendant of the TField type appropriate for the data type of the field. For example, when you add the CustNo field to the data set, Delphi adds a TFloatField object; when you add the Company field, Delphi adds a TStringField, and so on. This tutorial uses the general term TField when the specific data type is unimportant.
31
Note
Specifying a list of fields in the Database Form Expert is not the same as using the Fields Editor to define a dataset. The expert places components and controls in a form to create an initial layout, but you must use the Fields Editor to specify the fields in a data set. Use TField components, not visual controls, to access fields programmatically. Understanding the relationship between a TTable component, TField components, and data-aware controls is crucial to building database applications with Delphi.
What to do
1 Use the Database Form Expert to build a single-table form that displays all the fields of CUSTOMER.DB in a grid. For detailed instructions, see page 21. (If youre working through these examples in sequence, you can use the form from the previous example and skip to step 5.) 2 To make the grid display data at design time, use the Object Inspector to change the TTable components Active property to True. This step is optional: it lets you see what happens to the form as you use the Fields Editor. 3 Open the Fields Editor by double-clicking the TTable component. By default, the list of fields is empty. 4 Click Add to open a dialog box listing the fields in the Customer table. By default, all fields are selected. Control-click to select only the CustNo, Company, Phone, and LastInvoiceDate fields, then click OK to confirm your choices and close the dialog box. In the form, the grid changes: instead of displaying all fields, it displays the only the fields you selected. 5 Click the CustNo field in the Fields Editors field list and view the properties and values displayed in the Object Inspector. (To open the Object Inspector, choose View|Object Inspector.) Notice that the components Name property is Table1CustNo. Delphi generates this name automatically by appending the field name to the name of the associated TTable component. Use this name to refer to the TField component in code.
32
6 Change the Align property from taRightJustify (the default) to taCenter. In the form, the grid changes: values in the CustNo column are centered.
Figure 2.9 TField component properties
To display a TField components properties in the Object Inspector, choose a field name from the list in the Fields Editor. Delphi generates a TField components name by appending the field name to the name of the associated TTable component. Use this name to refer to the TField in code.
How it works
When you select a field listed in the Fields Editor, you can use the Object Inspector to set an invisible TField components properties, just as you would a visible control. Note that a fields display attributes are properties of the TField component, not of the control that displays the value! You only have to set a property once for the TField component. Linked controls use the settings automatically. This is a guiding principle of Delphi database applications: use TField components to work with database fields. The following table lists important TField design-time properties.
Table 2.8
Property
Alignment Calculated DisplayLabel DisplayWidth DisplayFormat and EditMask FieldName Index Name
ReadOnly Visible
33
Setting a TField components properties, see page 79. Using the Fields Editor, see page 30. Using the Database Form Expert, see page 21.
What to do
1 Use the Database Form Expert to build a single-table form that displays all the fields of CUSTOMER.DB in a grid. For detailed instructions, see page 21. 2 Use the Object Inspector to change the forms Name property to TutorialForm. 3 Open the Fields Editor by double-clicking the TTable component. By default, the list of fields is empty. 4 Click Add to open a dialog box listing the fields in the Customer table. By default, all fields are selected. Control-click to select only the CustNo, Company, Phone, and LastInvoiceDate fields, then click OK to confirm your choices and close the dialog box. The Fields Editor remains open. 5 Place a button control and a standard edit box anywhere in the panel that contains the TDBNavigator control (you may need to resize the panel), then set the edit box Name property to OutputField. 6 Attach the following code to the buttons OnClick event:
procedure TTutorialForm.Button1Click(Sender: TObject); begin OutputField.Text := Table1Company.Value; end;
7 Press F9 to run the form. Click a field in the grid, then click the button. The text in the edit control displays the value of the Company field for the current record.
How it works
The code in step 7 does a simple assignment: the edit controls Text property gets the value of the TField component named Table1Company, where the TFields value is the value of the corresponding field in the current record of the table.
Note
In code, refer to a TField by its component name, dont use the name of the field in the table. For example, use Table1Company, not Company. You can assign the TField components value directly to the Text property because Table1Company is of type TStringField. An edit boxs Text property and a TStringFields
34
Value property are of compatible types, so you dont need to do a conversion. However, the following code generates a type mismatch error at compile time, because Table1CustNo is of type TFloatField.
OutputField.Text := Table1CustNo.Value; {Causes a type mismatch error.}
To display a numeric fields value in an edit box, convert the value as follows.
OutputField.Text := Table1CustNo.AsString;
This code uses the TField property AsString to read the field value and convert it to a string before assigning it to the edit boxs Text property. TField components have the following properties for converting values: AsBoolean, AsDateTime, AsFloat, AsInteger, and AsString. The following code shows examples of how to read field values, display them in edit boxes, and assign them to variables.
var CustNoDouble: Double; CustNoInt: Integer; CustNoString: String; begin {Display field value in edit control.} OutputField.Text := Table1Company.Value; {Compatible types, no conversion.} OutputField.Text := Table1CustNo.AsString; {Convert field value to compatible type.} {Assign field value to variables.} CustNoDouble := Table1CustNo.Value; {Compatible types, no conversion.} CustNoInt := Table1CustNo.AsInteger; {Convert field value to compatible type.} CustNoString := Table1CustNo.AsString; {Convert field value to compatible type.} end;
What to do
1 Use the Database Form Expert to build a single-table form that displays all the fields of CUSTOMER.DB in a grid. For detailed instructions, see page 21. (If youre working through these examples in sequence, you can use the form from the previous example and skip to step 5.) 2 Use the Object Inspector to change the forms Name property to TutorialForm.
35
3 Open the Fields Editor by double-clicking the TTable component. By default, the list of fields is empty. 4 Click Add to open a dialog box listing the fields in the Customer table. By default, all fields are selected. Control-click to select only the CustNo, Company, Phone, and LastInvoiceDate fields, then click OK to confirm your choices and close the dialog box. 5 Place a button control and a standard edit box anywhere in the panel that contains the TDBNavigator control (you may need to resize the panel). 6 Attach the following code to the buttons OnClick event to change a companys name in the CUSTOMER table based on the current value in the standard edit box:
procedure TTutorialForm.Button1Click(Sender: TObject); begin Table1.Edit; Table1Company.Value := Edit1.Text; Table1.Post; end;
7 Press F9 to run the form. Type a value into the edit box, then click the button and notice the value of the Company field in the current record in the grid. It should be the same as the text in the edit box.
How it works
The code in step 6 does three things: it puts the table into Edit state, assigns a value to the Company field of the current record, and posts the modified record back to the table (which takes the table out of Edit state). As this example shows, there is a difference between editing field values interactively using controls and editing field values in code. By default, the AutoEdit property of a TDataSource component is set to True. A user can type into a data-aware control to that data source and modify the value immediately. When the user moves off that record, changes are posted automatically. But, to modify TField component values based on values entered in a standard edit control, or to perform table modifications in code, you need to explicitly switch to Edit state, set the value, and post changes.
Note
You can safely call Edit even if youre already in Edit or Insert state. In such cases, calls to Edit have no effect. The TField component and the value you assign must be compatible. In the example, the edit controls Text property is compatible with Table1Company, a TStringField. However, the following code generates a type mismatch error at compile time, because Table1CustNo is a TFloatField.
Table1CustNo.Value := OutputField.Text; {Causes a type mismatch error.}
To assign the text of an edit control to a numeric field, convert the text as follows.
Table1CustNo.AsString := OutputField.Text;
This code uses the TField property AsString to convert the text before assigning it toTable1CustNo. TField components have the following properties for converting values: AsBoolean, AsDateTime, AsFloat, AsInteger, and AsString.
36
The following code shows examples of how to assign field values, converting them if necessary.
Table1CustNo.Value := 12340; Table1CustNo.AsInteger := 4321; Table1CustNo.AsString := 5678; Table2CustNo.Value := Table1CustNo.Value; {Assign value of one TField to another.} Table2.Fields[0] := Table1.Fields[0]; {Also assign value of one TField to another.}
What to do
1 Use the Database Form Expert to build a single-table form that displays all the fields of ITEMS.DB in a grid. For detailed instructions, see page 21. 2 Use the Object Inspector to change the forms Name property to OrderForm, change the TTable components Name property to Items, and change the TTable components Active property to True. 3 In this forms CreateForm procedure, change Table1 to Items. 4 Open the Fields Editor by double-clicking the TTable component. By default, the list of fields is empty. 5 Click Add to open a dialog box listing the fields in the Items table. By default, all fields are selected. Click OK to add all the fields to the data set and close the dialog box. In the form, the grid displays a column for each field in the data set.
37
6 Click Define to open the Define Field dialog box, then enter specifications for a calculated field named ExtPrice as shown in the following figure:
Figure 2.10 Defining a calculated field
Type the field name here. Delphi automatically creates a name for the TField component by combining the name you type with the name of the TTable component. Choose a data type from this list. Check Calculated to specify a calculated field. Enter the number of characters to display (leave it blank for this tutorial example).
7 Click OK to accept values and close the dialog box. In the form, an empty ExtPrice column appears in the grid. You may have to scroll the grid to the right to see it. 8 Click Define again, then enter specifications for a second calculated field named ItemsSellPrice. It, too, should be given a CurrencyField data type. Click OK. 9 Double click the OnCalcFields event of the TTable component to open the code window, then enter the following code.
procedure TOrderForm.ItemsCalcFields(DataSet: TDataSet); begin if Parts.FindKey([ItemsPartNo]) then begin ItemsDescription.Value := PartsDescription.Value; ItemsSellPrice.Value := PartsListPrice.Value; end; ItemsExtPrice.Value := ItemsQty.Value * ItemsSellPrice.Value * (100 - ItemsDiscount.Value) / 100; end;
10 Type F9 to run the form. The ExtPrice column fills with calculated values. A calculated field does not display values at design time.
How it works
This form is the basis for the full-featured EDORDERS.DFM form in MASTAPP. It demonstrates the two key aspects of creating a calculated field in Delphi: adding the calculated field to a TTable components data set, and writing code to handle the TTable components OnCalcFields event. Delphi sends an OnCalcFields event each time the cursor for that table changes. The calculation accesses data through the TField components created in the Fields Editor, not the controls placed in the form. The example attaches code to the OnCalcFields event to update the value of the calculated field. You can use the OnCalcFields event for other purposes; for example, to do a lookup into another table, perform a complex calculation, or do real-time data
38
acquisition. However, in an OnCalcFields event, you can only assign values to calculated fields.
What to do
1 Use the Database Form Expert to build a single-table form that displays all the fields of CUSTOMER.DB. Specify a vertical layout and labels aligned left. For detailed instructions, see page 21. 2 Use the Object Inspector to change the forms Name property to EdCustForm, change the TTable components Name property to Cust, and change the TTable components Active property to True. In the form, notice the Tax Rate fields display format (example: 8.5). 3 In this forms CreateForm procedure, change Table1 to Cust. 4 Open the Fields Editor by double-clicking the TTable component. By default, the list of fields is empty. 5 Click Add to open a dialog box listing the fields in the Customer table. By default, all fields are selected. Click OK to add all the fields to the data set and close the dialog box. 6 In the Field Editors list of fields, choose Tax Rate, then use the Object Inspector to view the properties of the TFloatField named CustTaxRate. The DisplayFormat property is blank. 7 In the Object Inspector, enter the following value for the DisplayFormat property of CustTaxRate: 0.00%. In the form, the Tax Rate fields display format changes (example: 8.50%).
39
How it works
Delphi provides several properties that specify a fields display format. The following table lists some of the most frequently-used properties. Any data-aware control linked to a TField component uses the TFields display properties.
Table 2.9
Property
Alignment Currency DisplayFormat DisplayWidth DisplayFormat and EditMask FieldName Index Name
Visible
What to do
1 Use the Database Form Expert to build a single-table form that displays all the fields of CUSTOMER.DB. (If youre working through these examples in sequence, you can use the form from the previous example and skip to step 6.) Specify a vertical layout and labels aligned left. For detailed instructions, see page 21. 2 Use the Object Inspector to change the forms Name property to EdCustForm, change the TTable components Name property to Cust, and change the TTable components Active property to True. In the form, notice the Phone field displays U.S phone numbers (example: 808-555-0269). 3 In this forms CreateForm procedure, change Table1 to Cust.
40
4 Open the Fields Editor by double-clicking the TTable component. By default, the list of fields is empty. 5 Click Add to open a dialog box listing the fields in the Customer table. By default, all fields are selected. Click OK to add all the fields to the data set and close the dialog box. 6 In the Fields Editors list of fields, choose Phone, then use the Object Inspector to view the events of the TStringField named CustPhone. 7 Double-click the OnGetText event to open the code window, then add code to handle the event as follows.
procedure TEdCustForm.CustPhoneGetText(Sender: TField; var Text: OpenString; DisplayText: Boolean); begin if DisplayText then begin Text := CustPhone.Value; Delete(Text, 4, 1); Insert('(', Text, 1); Insert(')', Text, 5); end; end;
In this sample code, DisplayText is True, meaning youre not actually editing the field in question, but modifying the display of the field. When DisplayText is True, characters that would be invalid for the user to enter, such as parentheses in this case, can be inserted into the field for display purposes only.
8 Press F9 to run the form. The Phone fields display format changes (example: (808)555-0269).
How it works
Use the OnGetText event to format field values. Delphi calls a TField components OnGetText method whenever its about to display the value of a field onscreen, for example, when redrawing a data-aware component. Delphi ignores a TField components DisplayFormat property when you add code to its OnGetText event. In this example, CustPhoneGetText copies the phone number string to variable Text, then uses the Insert and Delete procedures to place parentheses around the first three digits. This gives U.S. phone numbers a more traditional format: (713) 555-1212, instead of 713-555-1212 as stored in the file. The DisplayText property is True when a TField is displaying data but is not available for editing. When a TField is in Edit state, DisplayText is False.
Note
41
Using the Fields Editor, see page 30. Using the Database Form Expert, see page 21. Setting a TField components properties, see page 79.
What to do
This example shows how to display a record in the Customer table by searching for a customer number entered by the user.
1 Use the Database Form Expert to build a single-table form that displays fields from CUSTOMER.DB. Specify a vertical layout and labels aligned left. For detailed instructions, see page 21. 2 Place a button control in the panel that contains the TDBNavigator control. 3 Double-click the button to open a code window, then add code to handle the buttons OnClick event as follows.
procedure TForm2.Button1Click(Sender: TObject); var UserCustNo: String; begin UserCustNo := InputBox('Search', 'Enter a Customer Number:', ' '); if not Table1.FindKey([UserCustNo]) then MessageDlg('Not found.', mtInformation, [mbOK], 0); end;
4 Add the Dialogs unit to the uses clause of your form unit. The InputBox function used in the previous step resides in the Dialogs unit. 5 Press F9 to run the form. Click the button and enter a number in the input dialog box (try 1560). If that number is a customer number in the table, Delphi displays the corresponding record. Otherwise, it displays a dialog box.
How it works
FindKey takes an array, where each array value represents a value to search for in the corresponding key field in the table. FindKey searches for the first array value in the first key field, the second array value in the second key field, and so on. In this example, the array contains one value, so FindKey searches for it in the first key field of the table, which is CustNo. The following example shows how to search for the name Frank P. Borland in a table where the key fields are LastName, FirstName, and MiddleInital.
begin if not Table1.FindKey(['Borland', 'Frank', 'P.']) then MessageDlg('Not found.', mtInformation, [mbOK], 0); end;
42
43
The Terms field is a TDBComboBox control. The list items are hard-coded. See page 44.
The SoldBy field is a TDBLookupCombo control. It reads list items from a field (column) of a table. See page 45.
What to do (list)
The following steps describe how to create the drop-down list labeled Terms in the Edorders form in MASTAPP. The Terms field specifies the payment terms for an order. Allowed values are Prepaid, Net 30, and COD.
1 Open the MASTAPP project, then open the Edorders form. 2 Place a TTable component. Set its DatabaseName and TableName properties to link it to the Orders table. Change its Name property to Orders. 3 Place a TDataSource component. Set its DataSet property to the Orders TTable. Change its Name property to OrdersSource. 4 Place a TDBComboBox control. Set its properties as shown in the following table.
Table 2.10
Property
DataField DataSource Items
Remarks
The name of the field in the table this control is linked to. The TDataSource component this control is linked to. Each list item is on its own line. In other words, when you enter list items, press Enter after each item.
44
How it works
A TDBComboBox control works like a standard combo box control, but its linked to a field in a table. Its Items property stores the list items. When the user chooses an item from the list, that value is assigned to the corresponding data field in the current record. You can add list items by hand at design time or specify them in code at run time.
What to do (lookup)
The following steps describe how to create the drop-down lookup list labeled SoldBy in the Edorders form in MASTAPP. The combo box labeled SoldBy displays a list of employee names, but it stores employee numbers. When the user chooses a name from the list, Delphi looks up the corresponding employee number and writes that value to the Orders tables.
1 Open the MASTAPP project, then open the Edorders form. 2 Place two TTable components. Set the first components DatabaseName and TableName properties to link it to the Orders table, and change its Name property to Orders. Set the second components DatabaseName and TableName properties to link it to the Employee table, and change its Name property to Emps. 3 Place two TDataSource components. Set the first components DataSet property to the Orders TTable and change its Name property to OrdersSource. Set the second components DataSet property to the Emps TTable and change its Name property to EmpsSource. 4 Place a TDBLookupCombo control. Set its properties as shown in the following table.
Table 2.11
Property
DataSource DataField LookupSource LookupDisplay
Remarks
The TDataSource component this control is linked to. The name of the field in the table this control is linked to. The TDataSource component used to identify the table from which to look up field values. The field (column) this control reads from to display list values to the user. FullName is a calculated field in the table pointed to by LookupSource. The field to search for a value corresponding to the value in the LookupDisplay field. This value is assigned to the field specified in DataField.
LookupField
EmpNo
How it works
The TDBLookupCombo control dynamically accesses a column from a table (specified in LookupDisplay) and displays it to the user. When the user chooses an item, Delphi finds
45
the value in the table specified in LookupSource. Then it reads the value of the field specified in LookupField. Finally, it assigns that value to the field specified in DataField in the table specified in DataSource. In this example, Delphi fills a drop-down box with employee names from the FullName field of the Employee table. FullName is a calculated field defined for the Employee table. To see how FullName is calculated, select Employee TTable component, then examine its OnCalcFields event. When the user chooses a name from the list, Delphi reads the EmpNo field to get the employee number for that name. Then it assigns that value to the EmpNo field of the Orders table.
What to do
1 Open the MASTAPP project, then open the Edorders form. 2 Double-click the TTable component named Orders to open the Fields Editor. 3 In the Fields Editors list of fields, click SaleDate, then use the Object Inspector to view the events of the TDateTimeField component named OrdersSaleDate. 4 Double-click the OnValidate event to open the code window, then add code to handle the OnValidate event as follows.
procedure TOrderForm.OrdersSaleDateValidate(Sender: TField); begin if OrdersSaleDate.Value > Now then raise Exception.Create('Cannot enter a future date'); end;
How it works
To check field values after the user enters them, write code to handle the OnValidate event of the appropriate TField component. The example code raises an exception if the date a user enters is later than todays date. Make sure all fields are either initialized to a valid value in an OnNewRecord event, or have their TField Required properties set to True.
46
Working with TField components, see page 34. Using the Fields Editor, see page 30.
1 Use Form Expert to build a form based on a query of the Customer table (for detailed instructions, see page 21). Use only the CustNo, Company, and State fields (for simplicity). Specify a grid layout. 2 Use the Object Inspector to set the TQuery components Active property to True. The grid displays the query results (by default, the query selects all records). 3 Set the TQuery components Active property to False. The grid empties. (Active must be False to change the query.) 4 Use the Object Inspector to display the TQuery components SQL property, and type the following statement after the last line in the SQL statement in the String List Editor window:
where State = "HI"
47
6 Set the TQuery components Active property to True. The grid displays only those records where the value of the State field is HI. (Optional: Press F9 to run the form.)
Figure 2.12 Setting a TQuerys SQL property
How it works
Delphi reads the SQL statements assigned to the TQuery components SQL property and passes them to the server without any intermediate interpretation. (Use double quotes in SQL statements, not single quotes as in Pascal code.) The server executes the query and returns the results to Delphi, and Delphi displays the result set in the grid.
Note:
By default, a TQuery components RequestLive property is set to False. When RequestLive is False, the result set returned by a query is read-only. Users cannot modify data in the form. If you want users to be able to update data returned by a query of a single table, then you can set RequestLive to True to request a live result set. If the query is updateable, CanModify returns True.
1 Use Form Expert to build a form based on a query of the Customer table (for detailed instructions, see page 21). Use only the CustNo, Company, and State fields (for simplicity). Specify a grid layout. If youre working through these examples in sequence, you can use the form from the previous example.
48
2 Use the Object Inspector to display the TQuery components SQL property, and type the following statement after the last line in the SQL statement in the String List Editor window:
where State = :State
3 The SQL statement in the previous step contains the field name State and the parameter State (a parameter is an arbitrary string preceded by a colon). Click OK to close the String List Editor. 4 Right-click the TQuery component, then choose Define Parameters from the pop-up menu. The Define Parameters dialog box opens, ready for you to assign a field type and a value to the parameter State. 5 Choose a field type of String, and enter a value of FL, then click OK to close the dialog box.
Figure 2.13 Defining a query parameter
To define the parameter State, choose a field type of String and enter a value of FL.
6 Set the TQuery components Active property to True. The grid displays the query results (all records where State = FL). 7 Place a button control in the panel that contains the TDBNavigator control. 8 Double-click the button to open a code window, then write the following code to handle its OnClick event.
procedure TForm2.Button1Click(Sender: TObject); begin Query1.DisableControls; try Query1.Active := False; Query1.Params[0].AsString := 'HI'; Query1.Active := True; finally Query1.EnableControls; end; end;
9 Press F9 to run the form, then click the button. The grid displays the query results (all records where State = HI).
How it works
In a SQL statement, a string preceded by a colon (like :State in the example) represents a parameter. At design time, Delphi recognizes parameters and displays them in the
49
Define Parameters dialog box. Then at run time, it assigns the specified values to the corresponding parameters. You can assign values to query parameters at run time using the Params property. It stores parameter values in an array, where an index of 0 represents the first parameter, an index of 1 represents the second parameter, and so on. So, this statement assigns the value HI to the first parameter.
Query1.Params[0].AsString := 'HI';
You need to set the TQuery components Active property to False before setting parameter values, then set it to True again to update the query. The calls to DisableControls and EnableControls, respectively, freeze and restore display capabilities of controls linked to the TQuery component. This disables data-aware control while the result set is updated.
Setting a range
This example explains how to select a set of records by setting a range (also called a filter). To set a range on a Paradox or dBASE table, work with keyed (indexed) fields. To set a range on a SQL table, you can specify the fields to be used as indexes using the IndexFieldNames property.
What to do
1 Use the Database Form Expert to build a single-table form that displays all the fields of CUSTOMER.DB in a grid. For detailed instructions, see page 21. 2 Use the Object Inspector to change the forms Name property to CustForm, change the TTable components Name property to Cust, and change the TTable components Active property to True. 3 In this forms CreateForm procedure, change Table1 to Cust. 4 Open the Fields Editor by double-clicking the TTable component. By default, the list of fields is empty. 5 Click Add to open a list box for the fields in the Items table. By default, all fields are selected. Click OK to add all the fields to the data set and close the list box. Close the Fields Editor. In the form, the grid displays a column for each field in the data set. 6 Place a button control in the panel that contains the TDBNavigator control.
50
7 Double-click the button to open a code window, then add code to handle the buttons OnClick event as follows.
procedure CustForm.Button1Click(Sender: TObject); begin Cust.DisableControls; try Cust.SetRangeStart; CustCustNo.Value := 3000; Cust.KeyExclusive := False; Cust.SetRangeEnd; CustCustNo.Value := 4000; Cust.KeyExclusive := True; Cust.ApplyRange; finally Cust.EnableControls; end; end;
8 Press F9 to run the form, then click the button. The grid displays records for customer numbers from 3,000 to 3,999.
How it works
This example sets a range to include records for customer numbers from 3,000 to 3,999. Setting a range on a table affects the values displayed in data-aware components linked to that table. Thats why the routine in step 7 begins by calling Cust.DisableControls and ends by calling Cust.EnableControls. DisableControls disables the display capabilities of controls linked to the specified table; in effect, it freezes them. EnableControls restores the controls to an active state.
Important
Always use a try. . . finally statement, followed by EnableControls. Otherwise, after an exception occurs, data controls are inactive. The call to Cust.SetRangeStart marks the beginning of a code block that sets the minimum value of the range. The next line assigns a value to the TField component named CustCustNo. (CustNo is the first and only key field in the Customer table.) Setting Cust.KeyExclusive to False indicates that the value is not to be excluded in the range. So, in this example, a customer number 3,000 would be included in the range. The call to Cust.SetRangeEnd marks the beginning of a code block that sets the maximum value of the range. The next line assigns a value to CustCustNo. Setting Cust.KeyExclusive to True indicates that the value is to be excluded from the range. A customer number 4, 000 would not be included. The call to Cust.ApplyRange puts the range settings into effect. (To cancel a range, call CancelRange.)
51
To run reports, the TReport component needs to locate the RS_RUN directory. You can put the RS_RUN directory in your DOS PATH, or you can put an EXEpath = entry in the Delphi RS_RUN.INI file.
1 Choose File|New Form to open the Browse Gallery, then choose Blank form and click OK to create a blank form. 2 Place a TReport component anywhere in the form. (The TReport component is on the Data Access components page.) 3 Use the Object Inspector to set the TReport components properties as shown in the following table.
Table 2.12
Property
Preview ReportDir
Remarks
When Preview is True, Delphi displays the report onscreen only; when Preview is False, Delphi sends the report to the printer. The path and directory where the report file resides.
ReportName
4 Place a button control anywhere in the form. 5 Double-click the button to open a code window, then write code to handle its OnClick event, as follows.
procedure TForm1.Button1Click(Sender: TObject); begin Report1.Run; end;
6 Press F9 to run the form. 7 Click the button to run the report. If the TReport components Preview property is set to True, Delphi displays the report onscreen; if Preview is False, Delphi sends the report to the printer.
How it works
The Run method of TReport opens the run-time version of ReportSmith, which prints or displays a report as specified by the TReport components properties. When youre designing a form, you can double-click a TReport component to open the full version of ReportSmith and build a report.
52
How it works
The Print method for the TForm class prints a form as it appears onscreen.
53
54
Chapter
Chapter 3
This chapter describes how to use key Delphi features and tools when building database applications, including: The TSession component. Dataset components (TTable and TQuery), their properties, and their methods. TDataSource components, their properties, and their methods. TField objects, their properties, and their methods. The Fields Editor to instantiate and control TField objects. TReport and TBatchMove components.
This chapter provides an overview and general description of data access components in the context of application development. For in-depth reference information on database components, methods, and properties, see the online VCL reference.
55
TDataSource, a conduit between dataset components and data-aware components. It appears on the Data Access component page. TFields, components corresponding to database columns, created either dynamically by Delphi at run time or at design time with the Fields Editor. Data controls use them to access data from a database. In addition, you can define calculated fields whose values are calculated based on the values of one or more database columns.
Figure 3.1 Delphi Data Access components hierarchy
This chapter describes most of these components and the tools that Delphi provides to work with them. The TQuery component is described in Chapter 5, Using SQL in applications. The TDatabase component is described in Chapter 6, Building a client/ server application.
56
preferable if an application will be repeatedly opening and closing tables in the database. If KeepConnections is False, a database connection will be closed as soon as the connection is inactive. The DropConnections method will drop all inactive database connections. The NetFileDir property specifies the directory path of the BDE network control directory. The PrivateDir property specifies the path of the directory in which to store temporary files (for example, files used to process local SQL statements). You should set this property if there will be only one instance of the application running at a time. Otherwise, the temporary files from multiple application instances will interfere with each other.
TSession methods
Returns
Defined BDE alias names. Parameters for the specified BDE alias. Database names and BDE aliases defined. Names of BDE drivers installed. Parameters for the specified BDE driver. All table names in the specified database.
For more information on these methods, see the online VCL Reference.
Using datasets
TTable and TQuery component classes are descended from TDataSet through TDBDataSet. These component classes share a number of inherited properties, methods, and events. For this reason, it is convenient to refer to them together as datasets, when the discussion applies to both TTable and TQuery. This section describes the features of datasets that are common to TTable and TQuery. A subsequent section discusses features unique to TTable. Chapter 5, Using SQL in applications describes features unique to TQuery.
Note
TStoredProc is also a dataset component since it is descended from TDBDataset. Therefore, much of this section also applies to TStoredProc if the stored procedure returns a result set rather than a singleton result. For more information on TStoredProc, see Chapter 6, Building a client/server application.
57
Dataset states
A dataset can be in the following states, also referred to as modes:
Table 3.2
State
Inactive Browse Edit Insert SetKey
Dataset states
Description
The dataset is closed. The default state when a dataset is opened. Records can be viewed but not changed or inserted. Enables the current row to be edited. Enables a new row to be inserted. A call to Post inserts a new row. Enables FindKey, GoToKey, and GoToNearest to search for values in database tables. These methods only pertain to TTable components. For TQuery, searching is done with SQL syntax. Mode when the OnCalcFields event is executed; prevents any changes to fields other than calculated fields. Rarely used explicitly.
CalcFields
An application can put a dataset into most states by calling the method corresponding to the state. For example, an application can put Table1 in Insert state by calling Table1.Insert or Edit state by calling Table1.Edit. A number of methods return a dataset to Browse state, depending on the result of the method call. A call to Cancel will always return a dataset to Browse state. CalcFields mode is a special case. An application cannot explicitly put a dataset into CalcFields mode. A dataset automatically goes into CalcFields mode when its OnCalcFields event is called. In OnCalcFields, an exception will occur if an application attempts to assign values to non-calculated fields. After the completion of OnCalcFields, the dataset returns to its previous mode. The following diagram illustrates the primary dataset states and the methods that cause a dataset to change from one mode to another.
58
Figure 3.2
Inactive Close Open SetKey * EditKey * Browse Post (Successful) Delete Edit SetKey Cancel GotoKey*, FindKey* Post
Post (Unsuccessful) The State property specifies the current state of a dataset. The possible values correspond to the above states and are dsInactive, dsBrowse, dsEdit, dsInsert, dsSetKey, and dsCalcFields. The OnStateChange event of TDataSource is called whenever the state of a data sources dataset changes. For more information, see Using TDataSource events on page 78.
Both of these statements open the dataset and put it into Browse state. Similarly, there are two ways to close a dataset: Set the datasets Active property to False, either at design time through the Object Inspector, or programmatically at run time. For example,
Query1.Active := False;
59
Navigating datasets
There are two important concepts in understanding how Delphi handles datasets: cursors and local buffers. Each active dataset has a cursor, which is essentially a pointer to the current row in the dataset. A number of rows of data before and after the cursor are fetched by Delphi into the local buffer. Delphi will always fetch a number of rows into the local buffer sufficient to display the current row, plus an additional number of rows to reduce the refresh time as the user scrolls up or down in the dataset:
Table 3.3 Navigational methods and properties
Description
Moves the cursor to the first row of a dataset. Moves the cursor to the last row of the dataset. Moves the cursor to the next row in the dataset. Moves the cursor to the prior row in the dataset. True when cursor is known to be at beginning of dataset, otherwise False. True when cursor is known to be at end of dataset, otherwise False. Moves the cursor n rows forward in dataset, where n is a positive or negative integer.
Method or property
First method Last method Next method Prior method BOF property EOF property MoveBy(n) method
Many of these methods are encapsulated in the TDBNavigator component. For more information on TDBNavigator, see Chapter 4, Using Data Controls.
Similarly, the Prior method moves the cursor up (backward) by one row in the dataset. For example, to move to the previous row in the table, a buttons OnClick text could be:
Table1.Prior
60
Similarly, the Last method moves to the last row in the dataset. To move to the last row in the table, a buttons OnClick text could be:
Table1.Last
After this code executes, BOF is False, even if there are no records before the current row. Once the table is open, Delphi can only determine BOF when an application explicitly calls First or a call to Prior fails. Similarly, Delphi can only determine EOF when an application explicitly calls Last or a call to Next fails. The following code sample demonstrates a common technique for using the BOF property:
while not Table1.BOF do begin DoSomething; Table1.Prior; end;
In this code sample, the hypothetical function DoSomething is called on the current record and then on all the records between the current record and the beginning of the dataset. The loop will continue until a call to Prior fails to move the current record back. At that point, BOF will return a value of True and the program will break out of the loop. To improve performance during the iteration through the table, call the DisableControls method before beginning the loop. This prevents data controls from displaying the iteration through the table, and speeds up the loop. After the loop completes, call the EnableControls method. Make sure to use a try...finally...end statement with the call to EnableControls in the finally clause. Otherwise, an exception will leave the applications controls inactive. The same principles apply to the EOF property, which returns a value of True after: An application opens an empty dataset A call to a Tables Last method A call to a Tables Next fails
61
The following code sample provides a simple means of iterating over all the records in a dataset:
Table1.DisableControls; try Table1.First; while not Table1.EOF do begin DoSomething; Table1.Next; end; finally Table1.EnableControls; end.
In this case, the Next method and the EOF property are used together to reach the end of the dataset.
Caution
A common error in using such properties in navigating a dataset is to use a repeat. . . until loop while forgetting to call Table1.Next, as in the following example:
Table1.First; repeat DoSomething; until Table1.EOF;
If code like this were executed, the application would appear to freeze, since the same action would be endlessly performed on the first record of the dataset, and the EOF property would never return a value of True. On an empty table, opening or executing any navigational methods will return True for both BOF and EOF.
When using this function, keep in mind that datasets are fluid entities, and the record which was five records back a moment ago may now be only four records back, or six records, or an unknown number of records, because multiple users may by simultaneously accessing the database and modifying its data.
Note
There is no functional difference between calling Table1.Next and calling Table1.MoveBy(1), just as there is no functional difference between calling Table1.Prior or calling Table1.MoveBy(1).
62
Post is not called implicitly by the Close method. Use the BeforeClose event to post any pending edits explicitly.
Editing records
A dataset must be in Edit state before an application can modify records in the underlying table. The Edit method puts a dataset in Edit state. When in Edit state, the
63
Post method will change the current record. If a dataset is already in Edit state, a call to Edit has no effect. The Edit and Post methods are often used together. For example,
Table1.Edit; Table1.FieldByName('CustNo').AsString := '1234'; Table1.Post;
The first line of code in this example places the dataset in Edit mode. The next line of code assigns the string 1234 to the CustNo field. Finally, the last line posts, or writes to the database, the data just modified.
Deleting records
The Delete method deletes the current record from a dataset and leaves the dataset in Browse mode. The cursor moves to the following record.
Canceling changes
An application can undo changes made to the current record at any time, if it has not yet directly or indirectly called Post. For example, if a Table is in Edit state, and a user has changed the data in one or more fields, the application can return the record back to its original values by calling the Tables Cancel method. A call to Cancel always returns a dataset to Browse state.
64
Table 3.5
Method
Each method takes a comma-delimited array of values as its argument, where each value corresponds to a column in the underlying table. The values can be literals, variables, null, or nil. If the number of values in an argument is less than the number of columns in a dataset, then the remaining values are assumed to be null. For un-indexed tables, AppendRecord adds a record to the end of the table and InsertRecord inserts a record after the current cursor position. For indexed tables, both methods places the record in the correct position in the table, based on the index. In both cases, the methods move the cursor to the records position. SetFields assigns the values specified in the array of parameters to fields in the dataset. The application must first perform an Edit to put the dataset in Edit state. To modify the current record, it must then perform a Post. Since these methods depend explicitly on the structure of the underlying tables, an application should use them only if the table structure will not change. For example, the COUNTRY table has columns for Name, Capital, Continent, Area, and Population. If Table1 were linked to the COUNTRY table, the following statement would insert a record into the COUNTRY table:
Table1.InsertRecord(['Japan', 'Tokyo', 'Asia']);
The statement does not specify values for Area and Population, so it will insert Null values for these columns. The table is indexed on Name, so the statement would insert the record based on the alphabetic collation of Japan. To update the record, an application could use the following code:
Table1.Edit; Table1.SetRecord(nil, nil, nil, 344567, 164700000); Table1.Post;
This code assumes that the cursor will be positioned on the record just entered for Japan. It assigns values to the Area and Population fields and then posts them to the database. Notice the three nils that act as place holders for the first three columns, which are not changed.
65
UpdateMode specifies which columns are included in the WHERE clause of an UPDATE statement. If Delphi cannot find a record with the original values in the columns specified (if another user has changed the values in the database), Delphi will not make the update and will generate an exception. The UpdateMode property may have the following values: WhereAll (the default): Delphi uses every column to find the record being updated. This is the most restrictive mode. WhereKeyOnly: Delphi uses only the key columns to find the record being updated. This is the least restrictive mode and should be used only if other users will not be changing the records being updated. WhereChanged: Delphi uses key columns and columns that have changed to find the record being updated. For example, consider a COUNTRY table with columns for NAME (the key), CAPITAL, and CONTINENT. Suppose you and another user simultaneously retrieve a record with the following values: NAME = Philippines CAPITAL = Nairobi CONTINENT = Africa Both you and the other user notice that the information in this record is incorrect and should be changed. Now, suppose the other user changes CONTINENT to Asia, CAPITAL to Manila, and posts the change to the database. A few seconds later, you change NAME to Kenya and post your change to the database. If your application has UpdateMode set to WhereKey on the dataset, Delphi compares the original value of the key column (NAME = Philippines) to the current value in the database. Since the other user did not change NAME, your update occurs. You think the record is now [Kenya, Nairobi, Africa] and the other users thinks it is [Philippines, Asia," Manila]. Unfortunately, it is actually [Kenya, , Asia, Manila], which is still incorrect, even though both you and the other user think you have corrected the mistake. This problem occurred because you had UpdateMode set to its least restrictive level, which does not protect against such occurrences. If your application had UpdateMode set to WhereAll, the Delphi would check all the columns when you attempt to make your update. Since the other user changed CAPITAL and CONTINENT, Delphi would not let you make the update. When you retrieved the record again, you would see the new values entered by the other user and realize that the mistake had already been corrected.
Bookmarking data
It is often useful to mark a particular location in a table so that you can quickly return to it when desired. Delphi provides this functionality through bookmark methods. These methods enable you to put a bookmark in the dataset, and quickly return to it later.
66
The three bookmarking methods are GetBookmark GoToBookmark FreeBookmark These are used together. The GetBookmark function returns a variable of type TBookmark. A TBookmark contains a pointer to a particular location in a dataset. When given a bookmark, the GoToBookmark method will move an applications cursor to that location in the dataset. FreeBookmark frees memory allocated for the specified bookmark. A call to GetBookmark allocates memory for the bookmark, so an application should call FreeBookmark before exiting, and before every use of a bookmark. The following code illustrates a typical use of bookmarking:
procedure DoSomething; var Bookmark: TBookmark; begin Bookmark := Table1.GetBookmark; {allocate} Table1.DisableControls; {Disengage data controls} try Table1.First; while not Table1.EOF do begin {Do Something} Table1.Next; end; finally Table1.GotoBookmark(Bookmark); Table1.EnableControls; Table1.FreeBookmark(Bookmark); {deallocate} end; end;
Notice the careful positioning of statements in this code. If the call to GetBookmark fails, controls are not disabled. If it succeeds, the bookmark is always freed and controls are always enabled.
67
the table or the data it contains might have changed. Refreshing a table can sometimes lead to unexpected results. For example, if a user is viewing a record that has been deleted, then it will seem to disappear the moment the application calls Refresh. Similarly, data can appear to change while a user is viewing it if another user changes or deletes a record after the data was originally fetched and before a call to Refresh.
Dataset events
Description
Called before/after a dataset is opened. Called before/after a dataset is closed. Called before/after a dataset enters Insert state. Called before/after a dataset enters Edit state. Called before/after changes to a table are posted. Called before/after the previous state is canceled. Called before/after a record is deleted. Called when a new record is created; used to set default values. Called when calculated fields are calculated.
For more information on these events and methods of the TDataSet component, refer to the online VCL reference.
Abort a method
To abort a method such as an Open or Insert, raise an exception or call the Abort procedure in any of the Before methods (BeforeOpen, BeforeInsert, and so on). For example, the following code confirms a delete operation:
procedure TForm1.TableBeforeDelete (Dataset: TDataset); begin if MessageDlg('Delete This Record?', mtConfirmation, mbYesNoCancel, 0) = mrYes then Abort; end;
Using OnCalcFields
The OnCalcFields event is used to set the values of calculated fields. The AutoCalcFields property determines when OnCalcFields is called. If AutoCalcFields is True, then OnCalcFields is called when: The dataset is opened. Focus moves from one visual component to another, or from one column to another in a DBDataGrid.
68
A record is retrieved from the database. OnCalcFields is also called whenever a non-calculated fields value changes, regardless of the setting of AutoCalcFields. Typically, the OnCalcFields event will be called often, so it should be kept short. Also, if AutoCalcFields is True, OnCalcFields should not perform any actions that modify the dataset (or the linked dataset if it is part of a master-detail relationship), because this can lead to recursion. For example, if OnCalcFields performs a Post, and AutoCalcFields is True, then OnCalcFields will be called again, leading to another Post, and so on. If AutoCalcFields is False, then OnCalcFields is called when the datasets Post method is called (or any method that implicitly calls Post, such as Append or Insert). While the OnCalcFields event is executed, a dataset will be put in CalcFields mode. When a dataset is in CalcFields mode, you cannot set the values of any fields other than calculated fields. After OnCalcFields is completed, the dataset will return to its previous mode.
Using TTable
TTable is one of the most important database component classes. Along with the other dataset component class, TQuery, it enables an application to access a database table. This section describes the most important properties that are unique to TTable.
Neither of these properties can be changed when a table is openthat is, when the tables Active property is set to a value of True.
69
Extension of .DB or no file-name extension: Paradox table Extension of .DBF : dBASE table Extension of .TXT : ASCII table If the value of TableType is not Default, then the table will always be of the specified TableType, regardless of file-name extension.
Searching a table
TTable has a number of functions that will search for values in a database table: Goto functions Find functions The easiest way to search for values is with the Find functions, FindKey and FindNearest. These two functions combine the functionality of the basic Goto functions, SetKey, GoToKey, and GoToNearest, which are described first. In dBASE and Paradox tables, these functions can search only on index fields. In SQL tables, they can search on any fields, if the field name is specified in the IndexFieldNames property of the TTable. For more information, see Indexes on page 74. To search a dBASE or Paradox table for a value in a non-index field, use SQL SELECT syntax with a TQuery component. For more information on using SQL and TQuery components, see Chapter 5, Using SQL in applications.
The first line of code after begin puts Table1 in SetKey state. This indicates that the following assignment to the tables Fields property specifies a search value. The first column in the table, corresponding to Fields[0], is the index. In this example, the value the application searches for is determined by the text the user types into the edit control, Edit1. Finally, GoToKey performs the search, moving the cursor to the record if it exists. GoToKey is a Boolean function that moves the cursor and returns True if the search is successful. If the search is unsuccessful, it returns False and does not change the position of the cursor. For example,
70
If the search does not find a record with a first column matching Smith, the ShowMessage function displays a dialog box with the Record Not Found message. If a table has more than one key column, and you want to search for values in a sub-set of the keys, set KeyFieldCount to the number of columns on which you are searching. For example, if a table has three columns in its primary key, and you want to search for values in just the first, set KeyFieldCount to 1. For tables with multiple-column keys, you can search only for values in contiguous columns, beginning with the first. That is, you can search for values in the first column, or the first and second, or the first, second, and third, but not just the first and third. GoToNearest is similar, except it finds the nearest match to a partial field value. It can be used only for columns of string data type. For example,
Table1.SetKey; Table1.Fields[0].AsString := 'Sm'; Table1.GoToNearest;
If a record exists with Sm as the first two characters, the cursor will be positioned on that record. Otherwise, the position of the cursor does not change and GoToNearest returns False. If it is not searching on the primary index of a local table, then an application must specify the column names to use in the IndexFieldNames property or the name of the index to use in the IndexName property of the table. For example, if the CUSTOMER table had a secondary index named CityIndex on which you wanted to search for a value, you would need to set the value of the tables IndexName property to CityIndex. You could then use the following syntax when you searching on this field:
Table1.IndexName := 'CityIndex'; Table1.Open; Table1.SetKey; Table1.FieldByName('City').AsString := Edit1.Text; Table1.GoToNearest;
Because indexes often have non-intuitive names, you can use the IndexFieldNames property instead to specify the names of indexed fields. Each time an application calls SetKey, it must set all the field values for which it will search. That is, SetKey clears any existing values from previous searches. To keep previous values, use EditKey. For example, to extend the above search to find a record with the specified city name in a specified country, an application could use the following code:
Table1.EditKey; Table1.FieldByName('Country').AsString := Edit2.Text;
71
FindNearest is similar to GotoNearest, in that it will move the cursor to the row with the nearest matching value. This can be used for columns of string data type only. Both of these functions work by default on the primary index column. To search the table for values in other indexes, you must specify the field name in the tables IndexFieldNames property or the name of the index in the IndexName property.
Note
With Paradox or dBASE tables, these methods work only with indexed fields. With SQL databases, they can work with any columns specified in the IndexFieldNames property.
72
SetRangeStart and EditRangeStart SetRangeEnd and EditRangeEnd SetRange([Start Values], [End Values]) ApplyRange CancelRange
SetRangeStart indicates that subsequent assignments to field values will specify the start of the range of rows to include in the application. SetRangeEnd indicates that subsequent assignments will specify the end of the range of rows to include. Any column values not specified are not considered. The corresponding methods EditRangeStart and EditRangeEnd indicate to keep existing range values and update with the succeeding assignments. ApplyRange applies the specified range. If SetRangeStart has not been called when ApplyRange is called, then the start range will be the beginning of the table; likewise, if SetRangeEnd has not been called, the end range will be the end of the table. CancelRange cancels the range filter and includes all rows in the table. The SetRange function combines SetRangeStart, SetRangeEnd, and field assignments into a single statement that takes an array of values as its argument.
Note
With Paradox or dBASE tables, these methods work only with indexed fields. With SQL databases, they can work with any columns specified in the IndexFieldNames property. For example, suppose there is a form with a TTable component named Cust, linked to the CUSTOMER table. CUSTOMER is indexed on its first column (CustNo). The form also has two Edit components named StartVal and EndVal, and you have used the Fields Editor to create a TField component for the CustNo column. Then these methods could be applied (for example, in a buttons OnClick event) as follows:
Cust.SetRangeStart; CustCustNo.AsString := StartVal.Text; Cust.SetRangeEnd; if EndVal.Text <> '' then CustCustNo.AsString := EndVal.Text; Cust.ApplyRange;
Notice that this code first checks that the text entered in EndVal is not null before assigning any values to Fields. If the text entered for StartVal is null, then all records from the beginning of the table will be included, since all values are greater than null. However, if the text entered for EndVal is null, then no records will be included, since none are less than null. This code could be re-written using the SetRange function as follows:
if EndVal.Text <> '' then Cust.SetRange([StartVal.Text], [EndVal.Text]); Cust.ApplyRange;
73
This will include all records where LastName greater than or equal to Smith. The value specification could also be:
Table1.FieldByName('LastName').AsString := 'Sm';
This would include records which have LastName greater than or equal toSm. The following would include records with a LastName greater than or equal to Smith and a FirstName greater than or equal to J:
Table1.FieldByName('LastName').AsString := 'Smith'; Table1.FieldByName('FirstName').AsString := 'J';
Indexes
An index determines how records are sorted when a Delphi application displays data. By default, Delphi displays data in ascending order, based on the values of the primary index column(s) of a table. Delphi supports SQL indexes, maintained indexes for Paradox tables, and maintained .MDX (production) indexes for dBASE tables. Delphi does not support: Non-maintained indexes on Paradox tables. Non-maintained or .NDX indexes of dBASE tables. The IndexFieldCount property for a dBASE table opened on an expression index. The GetIndexNames method returns a list of the names of available indexes on the underlying database table. For Paradox tables, the primary index is unnamed and therefore not returned by GetIndexNames. To use a primary index on a Paradox table, set the corresponding TTables IndexName to a null string. IndexFields is an array of field names used in the index. IndexFieldCount is the number of fields in the index. IndexFieldCount and IndexFields are read-only properties that are available only during run-time. Use the IndexName property to sort or search a table on an index other than the primary index. In other words, to use the primary index of a table, you need do nothing with the IndexName property. To use a secondary index, however, you must specify it in IndexName. For tables in a SQL database, the IndexFieldNames property specifies the columns to use in the ORDER BY clause when retrieving data. The entry for this property is a
74
semicolon-delimited list of field names. Records are sorted by the values in the specified fields. Sorting can be only in ascending order. Case-sensitivity depends on the server being used. For example, to sort customer records in an SQL table by zip code and then by customer number, enter the following for the IndexFieldNames property:
ZipCode;CustNo
For Paradox and dBASE tables, Delphi will pick an index based on the columns specified in IndexFieldNames. An error will occur if you specify a column or columns that cannot be mapped to an existing index. The IndexName and IndexFieldNames properties are mutually exclusive. Setting one property clears the value of the other.
75
When CanModify is False, then the table is read-only, and the dataset cannot be put into Edit or Insert state. When CanModify is True, the dataset can enter Edit or Insert state. Even if CanModify is True, it is not a guarantee that a user will be able to insert or update records in a table. Other factors may come in to play, for example, SQL access privileges.
The Field Link Designer provides a visual way to link master and detail tables. The Available Indexes combo box shows the currently selected index by which to join the two tables. For Paradox tables, this will be Primary by default, indicating that the primary index of the detail field will be used. Any other named indices defined on the table will be shown in the drop-down list.
76
Select the field you want to use to link the detail table in the Detail Fields list, the field to link the master table in the Master Fields list, and then choose Add. The selected fields will be displayed in the Joined Fields list box. For example,
OrderNo -> OrderNo
For tables on a database server, the Available Indexes combo box will not appear, and you must select the detail and master fields to join manually in the Detail Fields and Master Fields list boxes.
Using TDataSource
TDataSource acts as a conduit between datasets and data-aware controls. Often the only thing you will do with a TDataSource component is to set its DataSet property to an appropriate dataset object. Then you will set data controls DataSource property to the specific TDataSource. You also use TDataSource components to link datasets to reflect master-detail relationships.
77
Similarly, OnStateChange can be used to enable or disable buttons or menu items based on the current state. For example,
procedure Form1.DataSource1.StateChange(Sender: TObject); begin InsertBtn.Enabled := (Table1.State = dsBrowse);
78
79
The Fields list box displays the names of persistent TField components associated with the data access component. The first time you invoke the Fields Editor on a particular a TTable or TQuery component, the Fields list is empty because all TFields are dynamically created. If any TField objects are listed in Fields, then data-aware components can only display data from those fields. You can drag and drop individual TField objects within the Field list box to change the order in which fields are displayed in controls, like TDBGrid, that display multiple columns.
80
The navigator buttons at the bottom of the Fields Editor window enable you to scroll through the records one at a time, and to jump to the first or last record of the dataset if it is active. The Add button enables you to see a list of column names in the physical dataset but not already included in the Fields list, and to create new TField components for them. The Define button enables you to create calculated fields. Fields created this way are only for display purposes. The underlying physical structure of the table or data is not changed. The Remove button deletes the selected TFields. The Clear All button deletes all the TFields shown in the Fields list.
The Available Fields list box shows all database fields that do not have persistent TFields instantiated. Initially, all available fields are selected. Use the mouse to select specific fields and then choose OK. The selected fields move to the Fields list box in the main Fields Editor window. Fields moved to the Available Fields list become persistent. Each time the dataset is opened, Delphi verifies that each non-calculated field exists or can be created from data in the database. If it cannot, an exception is raised, warning you that the field is not valid, and the dataset is not opened.
81
1 Choose the Define button in the Fields Editor window. 2 Enter the name of the new field in the Field Name edit box, or select a field name from the drop-down list. A corresponding TField component name appears automatically in the Component edit box as you type. This name is the identifier you use to access the field programmatically. 3 Select the data type for the field from the Field Type list box. 4 Check the Calculated check box if it is not already checked. 5 Choose OK. The newly defined calculated field is automatically added to the Fields list box in the main Fields Editor window, and the component declaration is automatically added to the forms type declaration in the source code.
To edit the properties or events associated with the new TField component, select the component name in the Fields list box, then edit the properties or events via the Object Inspector.
82
For example, on Form1, the OnCalcFields event for a TTable component named Table1 is
TForm1.Table1CalcFields
1 Select the TTable or TQuery component from the Object Inspector drop-down list. 2 Choose the Object Inspector Events tab. 3 Double-click the OnCalcFields property to bring up or create a CalcFields procedure for the TTable or TQuery component. 4 Write the code that sets the values and other properties of the calculated field as desired.
TField properties
Purpose
Displays contents of field left justified, right justified, or centered within a data-aware component. True, field value can be calculated by a CalcFields method at run time. False, field value is determined from the current record. True, numeric field displays monetary values. False, numeric field does not display monetary values. Specifies the format of data displayed in a data-aware component. Specifies the column name for a field in a TDBGrid. Specifies the width, in characters, of a grid column that display this field. Specifies the edit format of data in a data-aware component. Limits data-entry in an editable field to specified types and ranges of characters, and specifies any special, non-editable characters that appear within the field (hyphens, parentheses, etc.). Specifies the actual name of column in the physical table from which the TField component derives its value and data type. Specifies the order of the field in a dataset. Specifies the maximum numeric value that can be entered in an editable numeric field.
83
Table 3.7
Property
MinValue Name ReadOnly Size Tag Visible
Not all properties are available to all TField components. For example, a component of type TStringField does not have Currency, MaxValue, or DisplayFormat properties. A component of type TFloatField does not have a Size property. Boolean properties, those that can be toggled between True and False, can be changed by double-clicking the property in the Object Inspector. Other properties require you to enter values or pick from drop-down lists in the Object Inspector. All TField properties can also be manipulated programmatically. While the purpose of most properties is straight-forward, some properties, such as Calculated, require additional programming steps to be useful. Others, such as DisplayFormat, EditFormat, and EditMask, are interrelated; their settings must be coordinated. For more information about using the Calculated property, see Programming a calculated field. For more information about using DisplayFormat, EditFormat, and EditMask, see Formatting fields.
84
To use one of the sample masks, select it in the Sample Masks list box. You can then customize the mask as desired by editing it in the Input Mask text field. You can test the allowable input in the Test Input field. For more information, see the online Help.
Note
For the TStringField, the EditMask property is also used as a display format.
Formatting fields
Delphi provides built-in display and edit format routines and intelligent default formatting for TField components. These routines and formats require no action on the programmers part. Default formatting conventions are based on settings in the Windows Control Panel. For example, using default Windows settings in the United States, a TFloatField column with the Currency property set to True sets the DisplayFormat property for the value 1234.56 to $1234.56, while the EditFormat is 1234.56. Only format properties appropriate to the data type of a TField component are available for a given component. All TField component formatting is performed by the following routines:
Table 3.8
Routine
FormatFloat FormatDateTime FormatInteger
The format routines use the International settings specified in the Windows Control Panel for determining how to display date, time, currency, and numeric values. You can edit the DisplayFormat and EditFormat properties of a TField component to override the default display settings for a TField, or you can handle the OnGetText and OnSetText events for a TField to do custom programmatic formatting.
OnGetText and OnSetText events are primarily useful to programmers who want to do custom formatting that goes beyond Delphis built-in formatting functions, FormatFloat, FormatDate, and so on. TFields have a FocusControl method that enables an event to set focus to the first dataaware control associated with the TField. This is especially important for record-oriented
85
validation (for example, on BeforePost of a TTable) since a TField may be validated whether or not its associated data control has focus.
TField Type
AsInteger
Convert to Integer if possible Integer type by definition Round to nearest integer value Not Allowed
AsFloat
Convert to Float if possible Convert to Float
AsDateTime
Convert to Date if possible Not Allowed
AsBoolean
Convert to Boolean if possible Not Allowed
Convert to String
Float type by definition Convert Date to number of days since 01/01/0001 Convert Time to fraction of 24 hours Not Allowed Not Allowed
Not Allowed
Not Allowed
Not Allowed
Convert to String True or False Convert to String (Generally only makes sense for TMemoField)
The conversion functions can be used in any expression involving a TField component, on either side of an assignment statement. For example, the following statement converts the value of the TField named MyTableMyField to a string and assigns it to the text of the Edit1 control:
Edit1.Text := MyTableMyField.AsString;
Conversely, this statement assigns the text of the Edit1 control to the TField as a string:
MyTableMyField.AsString := Edit1.Text;
86
Any properties of TField components that are available from the Object Inspector can also be accessed and adjusted programmatically as well. For example, this statement changes field ordering by setting the Index property of CustTableCountry to 3:
CustTableCountry.Index := 3;
Conversely, you can assign a value to a column a dataset in Edit mode by assigning the appropriate Fields property to the value of a component. For example,
CustTable.Fields[6].AsString := Edit1.Text;
To make these assignments occur, you must enter them in an event such as a TButton OnClick event, or an edit controls OnEnter event.
87
This method requires you to know the name of the column you want to access or if your application works with tables that are not available at design time. For example, the following statement assigns the value of the Country column in the CustTable table to Edit2:
Edit2.Text := CustTable.FieldByName('Country').AsString;
Conversely, you can assign a value to a column a dataset in Edit mode by assigning the appropriate FieldByName property to the value of a component. For example,
CustTable.FieldByName('Country').AsString := Edit2.Text;
To make these assignments occur, you must enter them in an event such as a buttons OnClick or a Edit components OnExit event.
For more information about creating and using report variables, see Creating Reports. Some important methods of TReport are listed in the following table:
Table 3.11
Method
Run RunMacro
88
Table 3.11
Method
Connect SetVariable ReCalcReport
Using TBatchMove
TBatchMove enables you to perform operations on groups of records or entire tables. The primary uses of this component are Downloading data from a server to a local data source for analysis or other operations. Upsizing a database from a desktop data source to a server. For more information on upsizing, see Appendix C, Using local SQL. TBatchMove is powerful because it can create tables on the destination that correspond to the source tables, automatically mapping the column names and data types as appropriate. Two TBatchMove properties specify the source and a destination for the batch move operation: Source specifies a dataset (a TQuery or TTable component) corresponding to an existing source table. Destination specifies a TTable component corresponding to a database table. The destination table may or may not already exist.
batCopy batDelete
The Transliterate property specifies whether to transliterate character data to the preferred character set for the destination table.
89
To batch move data to an SQL server database, you must have that database server and Delphi Client/Server edition with the appropriate SQL Link installed. For more information, see the SQL Links for Windows Users Guide:
Physical data type translations from Paradox tables to tables of other driver types
To dBASE type
Character Float {20.4} Float {20.4} Date Number {6.0} Memo Memo Memo OLE Binary Number {11.0} Character {>8} Character {>8} Bool Number{11.0} Memo N/A
Table 3.13
To Oracle type
Character Number Number Date Number Long LongRaw LongRaw LongRaw LongRaw Number Character {>8} Date Character {1} Number LongRaw N/A
To Sybase type
VarChar Float Money DateTime SmallInt Text Image Image Image Image Int Character {>8} DateTime Bit Int Image N/A
To InterBase type
Varying Double Double Date Short Blob/1 Blob Blob Blob Blob Long Character {>8} Date Character {1} Long Blob N/A
To Informix type
Character Float Money {16.2} Date SmallInt Text Byte Byte Byte Byte Integer Character {>8} DateTime Character Integer Byte N/A
Table 3.14
Physical data type translations from dBASE tables to tables of other driver types
To Paradox type
Alpha Short Number Number Date Memo Bool Alpha {24} OLE
To Oracle type
Character Number Number Number Date Long Character {1} Character {24} LongRaw
To Sybase type
VarChar SmallInt Float Float DateTime Text Bit Character {24} Image
To InterBase type
Varying Short Double Double Date Blob/1 Character {1} Character {24} Blob
To Informix type
Character SmallInt Float Float Date Text Character Character Byte
90
Table 3.14
Physical data type translations from dBASE tables to tables of other driver types (continued)
To Paradox type
Binary Bytes
To Oracle type
LongRaw LongRaw
To Sybase type
Image Image
To InterBase type
Blob Blob
To Informix type
Byte Byte (only for temp tables)
Table 3.15
Physical data type translations from InterBase tables to tables of other driver types
To Paradox type
Short Number Number Number Alpha Alpha DateTime Binary Memo
To dBASE type
Number {6.0} Number {11.0} Float {20.4} Float {20.4} Character Character Date Memo Memo
To Oracle type
Number Number Number Number Character Character Date LongRaw Long
To Sybase type
Small Int Int Float Float VarChar VarChar DateTime Image Text
To Informix type
SmallInt Integer Float Float Character Character DateTime Byte Text
By default TBatchMove matches columns based on their position in the source and destination tables. That is, the first column in the source is matched with the first column in the destination, and so on. To override the default column mappings, use the Mappings property. This is a list of column mappings (one per line) in one of two forms. To map the column, ColName, in the source table to the column of the same name in the destination table:
ColName
Or, to map the column named SourceColName in the source table to the column named DestColName in the destination table:
DestColName = SourceColName
If source and destination column data types are not the same, TBatchMove will perform a best fit. It will trim character data types, if necessary, and attempt to perform a limited amount of conversion if possible. For example, mapping a CHAR(10) column to a CHAR(5) column will result in trimming the last five characters from the source column. As an example of conversion, if a source column of character data type is mapped to a destination of integer type, TBatchMove will convert a character value of 5 to the corresponding integer value. Values that cannot be converted will generate errors. See Handling batch move errors on page 92.
91
You can also execute a batch move at design time by right clicking the mouse on a TBatchMove component and choosing Execute. The MoveCount property keeps track of the number of records that were moved when a batch move is executed.
92
The application must include the header files that reference the BDE: DBIPROCS.PAS and DBITYPES.PAS. Then the code can make direct calls to the BDE application programming interface. BDE function calls often require parameters to specify the action to be performed. Delphi provides access to these through the following properties of dataset components: DBHandle is the handle for the database to which they are connected. Handle is the handle for the underlying cursor on the database. DBLocale and Locale are used for ANSI/OEM conversion for localization of applications. After performing a BDE call directly, it is a good idea to call Refresh to ensure that all data-aware components are synchronized with their datasets.
Application examples
This section provides some brief examples of specific database tasks, illustrating some of the material presented in the preceding sections.
1 Place two TTable, two TDataSource, and two TDBDataGrid components on a form. 2 Set the properties of the first TTable component as follows: DatabaseName: DBDEMO (the alias for the directory with the MAST database). TableName: CUSTOMER (the table containing customer records). Name: CustTable (for ease-of-use). 3 Name the first TDataSource component CustDataSource, and set its Dataset property to CustTable. Set the DataSource property of DBGrid1 to CustDataSource. When you activate CustTable (by setting its Active property to True), the grid displays the data in the CUSTOMER table. 4 Analogously, set the properties of the second TTable component as follows: DatabaseName: DBDEMO. TableName: ORDERS (the table containing order records). Name: OrdTable (for ease-of-use). 5 Name the second TDataSource component OrdDataSource, and set its Dataset property to OrdTable. Set the DataSource property of DBGrid2 to OrdDataSource. When you activate OrdTable (by setting its Active property to True), the grid displays the data in the ORDERS table.
93
6 Compile and run the application now. The form displays data from each table independently and should look something like this:
Figure 3.8 Sample form
7 The next step is to link the ORDERS table (the master table) to the CUSTOMER table (the detail table) so that the form displays only the orders placed by the current customer. To do this, exit the application, return to design mode, and set the MasterSource property of OrdTable to CustDataSource. 8 In the Object Inspector, click on the ellipsis button to the right of the MasterFields property of OrdTable. The Field Link Designer dialog box will open. In the Available Indexes field, choose ByCustNo to link the two tables by the CustNo field. Select CustNo in both the Detail Fields and Master Fields field lists. Click on the Add button to add this join condition. In the Joined Fields list, CustNo -> CustNo will appear. Choose OK to commit your selections and exit the Field Link Designer.
If you run the application now, you will see that the tables are linked together, and that when you move to a new record in the CUSTOMER table, you see only those records in the ORDERS table that belong to the current customer. The MasterSource property specifies the TDataSource from which OrdTable will take its master column values. This limits the records it retrieves, based on the current record in CustTable. To do this, you must specify for OrdTable: The name of the column that links the two tables. The column must be present in each table, and must be identically named. The index of the column in the ORDERS table that will be linked to the CUSTOMER table. In addition, you must ensure that the ORDERS table has an index on the CustNo field. Since it is a primary index, there is no need to specifically name it, and you can safely leave the IndexName field blank in both tables. However, if the table were linked through a secondary index, you must explicitly designate that index in the IndexName property. In this example, the CUSTOMER table has a primary index on the CustNo column, so there is no need to specify the index name. However, the ORDERS table does not have a
94
primary index on CustNo, so you must explicitly declare it in the IndexName property, in this case ByCustNo
Note
You can also set the IndexFieldNames property to CustNo, and the correct index will be supplied for you.
Once the second TDataSource is assigned to a valid dataset, both forms will remain synchronized. The TWOFORMS.DPR example in \DELPHI\DEMOS\DB\TWOFORMS demonstrates how to work with multiple forms and a single dataset. The program opens the COUNTRY table and shows the Name, Capital, and Continent fields on one form, and the Area and Population fields on a second form. A button on the first form opens the second form. Both forms have TDBNavigator components, so you can navigate through the table. The forms look like this:
Figure 3.9 Two forms
1 Place a TTable, a TDataSource, a TButton, three TDBEdit, and three TLabel components on a form.
95
2 Give the Button the name Detail. 3 Set the Table1s DatabaseName property to the DBDemos alias, and open the COUNTRY Table. 4 Connect DataSource1 to Table1, then connect each of the DBEdit components Datasource properties to DataSource1. By performing these steps in this order, you can drop down a list in the DataField property of the data aware controls. 5 Create a second form, and place a data source, a TBitBtn, two TDBLabels, a TDBNavigator and two TDBEdit controls on the form. Dont yet connect the data source on this form to anything else. 6 Connect the DBEdit components to the DataSource, then enter Area for the DataField property of DBEdit1, and Population for DBEdit2. 7 Set the Kind property of the bitbutton to OK. 8 Name this second form DetailView, then save the whole unit under the name DETAILS.PAS.
Note
When you are creating the second form, you might find it helpful to temporarily create a TTable component and link the data source to it. This enables you to design the form using live data, and gives you access to a list of field names for each edit control. Once you have the form set up properly, you can delete the TTable component and at run time reconnect the data source to a table on a separate form. Once you have built the second form, go back to the first form and add DETAILS to the uses clause in the form units implementation part, and create the following event handler for the OnClick event of the Detail button:
procedure TForm1.DetailClick(Sender: TObject); begin DetailView.DataSource1.DataSet := Table1; DetailView.Visible := True; end;
This code first assigns the data source on the second form to the table in the first form. Once this connection is made, then the data source on the second form is live. That is, it will act exactly like the data source on the first form. Then it makes the form visible. Now, connect the navigators on each form to the appropriate data source. When you run the program, open the second form by clicking on the Detail button. Notice that whether you use the navigator in either form, the edit controls on the other form remain synchronized with the current record. Close the application and add two more lines of code to the second forms unit. This code is called in response to a click on the OK button:
procedure TDetailView.BitBtn1Click(Sender: TObject); begin DataSource1.DataSet := nil; Close; end;
96
This code sets the dataset to nil whenever the second form is closed. While not necessary, this ensures that the hidden detail view is not responding to events.
97
98
Chapter
Chapter 4
To display and edit data from a database, use the components on the Data Controls page of the Component palette. Data controls include components such as TDBGrid for displaying and editing all specified records and fields in a table, and TDBNavigator for navigating among records, deleting records, and posting records when they change.
Figure 4.1 Data Controls Component palette
The following table summarizes the data controls in order from left to right as they appear on the Component palette:
Table 4.1
TDBGrid
Data controls
Description
Displays information from a data source in a spreadsheet-like grid. Columns in the grid can be specified at design time using the Fields Editor or at run time (dynamically bound). Provides buttons for navigating through data obtained from a data source. At design time, you can choose to include one or more buttons to navigate through records, update records, post records, and refresh the data from the data source. Displays data from a specific column in the current data record. Uses an edit box to display and edit data from a specific column in the current data record. Displays memo-type database data. Memo fields can contain multiple lines of text or can contain BLOB (binary large object) data. Displays graphic images and BLOB data from a specific column in the current data record. Displays a list of items from which a user can update a specific column in the current data record. Combines a TDBEdit control with an attached list. The application user can update a specific column in the current data record by typing a value or by choosing a value from the drop-down list.
Data control
TDBNavigator
99
Table 4.1
Data control
TDBCheckBox TDBRadioGroup TDBLookupList TDBLookupCombo
Most data controls are data-aware versions of standard components. Some, such as TDBGrid and TDBNavigator, are data-aware, but differ from standard components in significant, useful ways. A data-aware control derives display data from a database source outside the application, and can also optionally post (or return) data changes to a data source. Data controls are data-aware at design time, meaning that when you connect a component to an active data source while building an application, you can immediately see live data in the controls. You can use the Fields Editor to scroll through records at design time to verify that your application is making the right database connections without requiring you to compile and run the application, but you cannot modify data at design time. This chapter describes basic features common to all Data Control components, then describes how and when to use individual components.
100
2 Set the DataSource property to the name of a TTable or TQuery component already on the form. You can type the name or choose it from the drop-down list. 3 Set the DataField property to the name of a TField component. You can type the field name or choose it from the drop-down list.
Note
Two data controls, TDBGrid and TDBNavigator, access all available TField components within a dataset, and therefore do not have DataField properties. For these controls, omit step 3. When a data control is associated with a dataset, its Enabled property determines if its attached TDataSource component receives data from mouse, keyboard, or timer events. Controls are also disabled if the Enabled property of TDataSource is False, or if the Active property of the dataset is False.
Updating fields
Most data controls can update fields by default. Update privileges depend on the status of the controls ReadOnly property and underlying TFields and datasets CanModify property. ReadOnly is set to False by default, meaning that data modifications can be made. In addition, the data source must be in Edit state if updates are to be permitted. The data source AutoEdit property, set to True by default, ensures that the dataset enters Edit mode whenever an attached control starts to modify data in response to keyboard or mouse events. In all data controls except TDBGrid, when you modify a field, the modification is copied to the underlying TField component when you Tab from the control. If you press Esc before you Tab from a field, then Delphi abandons the modifications, and the value of the field reverts to the value it held before any modifications were made. In TDBGrid, modifications are copied only when you move to a different record; you can press Esc in any record of a field before moving to another record to cancel all changes to the record. When a record is posted, Delphi checks all data-aware components associated with the dataset for a change in status. If there is a problem updating any fields that contain modified data, Delphi raises an exception, and no modifications are made to the record.
101
Figure 4.2
TDBText component
A TDBText control is useful when you want to provide display-only data on a form that allows user input in other controls. For example, suppose a form is created around the fields in a customer list table, and that once the user enters a street address, city, and state or province information in the form, you use a dynamic lookup to automatically determine the zipcode field from a separate table. A TDBText component tied to the zipcode table could be used to display the zipcode field that matches the address entered by the user.
Note
When you create a TDBText component on a form, make sure its AutoSize property is True (the default) to ensure that the control resizes itself as necessary to display data of varying widths. If AutoSize is set to False, and the control is too small, data display is truncated.
TDBEdit component
Editing a field
A user can modify a database field in a TDBEdit component if:
1 The Dataset is in Edit state. 2 The Can Modify property of the Dataset is True. 3 The ReadOnly property of TDBEdit is False.
Note
Edits made to a field must be posted to the database by using a navigation or Post button on a TDBNavigator component.
102
Record indicator
The appearance of records in TDBGrid depends entirely on whether the TField components of the dataset are dynamically created by Delphi at run time, or if you use the Fields Editor to create persistent set of TField components whose properties you can specify in the Object Inspector at design time. If Delphi generates a dynamic dataset at run time, then all records are displayed using default record and field ordering, and default display and edit formats. In most cases, however, you will want to control field order and appearance. To do so, use the Fields Editor to instantiate TField components and set their properties at design time. When you use the Fields Editor to instantiate TField components, you gain a great deal of flexibility over the appearance of records in a TDBGrid. For example, the order in which fields appear from left to right in TDBGrid is determined by the way you order TField components in the Fields list box of the Fields Editor. Similarly, the DisplayFormat and EditFormat properties of a TField component determine how that field appears in TDBGrid during display and editing, respectively. You can also ensure that a value is entered for a field in a new record by setting its Required property to True. You can even prevent a TField component from being displayed in a grid by setting its Visible property to False. For more information about using the Fields Editor to control TField properties, see Chapter 3, Using data access components and tools. To put a TDBGrid on a form and link it to a dataset:
1 Create the control on the form. 2 Set the DataSource property to the name of a TTable or TQuery component already on the form.
103
properties that you can set individually. To view and set these properties, double-click the Options property. The list of options that you can set appears in the Object Inspector below the Options property. The + sign changes to a (minus) sign, indicating that you can collapse the list of properties by double-clicking the Options property. The following table lists the Options properties that can be set, and describes how they affect the grid at run time:
Table 4.2
Option
dgEditing dgAlwaysShowEditor dgTitles dgIndicator
dgColumnResize
dgConfirmDelete
For more information about these options, see the online Help reference.
1 The CanModify property of the Dataset is True. 2 The ReadOnly property of TDBGrid is False.
104
In most data controls, edits to a field are posted as soon as you Tab to another control. By default in TDBGrid, edits and insertions within a field are posted only when you move to a different record in the grid. Even if you use the mouse to change focus to another control on a form, the grid does not post changes until you move off the current row. When a record is posted, Delphi checks all data-aware components associated with the dataset for a change in status. If there is a problem updating any fields that contain modified data, Delphi raises an exception, and does not modify the record. You can cancel all edits for a record by pressing Esc in any field before moving to another record.
TDBGrid events
Purpose
Specify action to take when a user moves into a column on the grid. Specify action to take when a user leaves a column on the grid. Specify action to take when a user double clicks in the grid. Specify action to take when a user drags and drops in the grid. Specify action to take when a user drags over the grid.
105
Table 4.3
Event
There are many uses for these events. For example, you might write a handler for the OnDblClick event that pops up a list from which a user can choose a value to enter in a column. Such a handler would use the SelectedField property to determine to current row and column. For more information about TDBGrid events and properties, see the online Help reference.
TDBNavigator component
Insert record Delete current record Post record edits Refresh records Cancel record edits
TDBNavigator buttons
Purpose
Calls the datasets First method to set the current record to the first record. Calls the datasets Prior method to set the current record to the previous record. Calls the datasets Next method to set the current record to the next record. Calls the datasets Last method to set the current record to the last record. Calls the datasets Insert method to insert a new record before the current record, and set the dataset in Insert state.
106
Table 4.4
Button
Delete Edit Post Cancel Refresh
As button values are set to False, they are removed from the TDBNavigator on the form, and the remaining buttons are expanded in width to fill the control. You can drag the controls handles to resize the buttons. For more information about buttons and the methods they call, see the online Help reference.
107
permits a user to enter multi-line text as well. For example, you can use TDBMemo controls to display memo fields from dBASE and Paradox tables and text data contained in BLOB fields.
Figure 4.6 TDBMemo component
By default, TDBMemo permits a user to edit memo text. To limit the number of characters users can enter into the database memo, use the MaxLength property. To make a TDBMemo component read-only, set its ReadOnly property to True. Several properties affect how the database memo appears and how text is entered. You can supply scroll bars in the memo with the ScrollBars property. To prevent word wrap, set the WordWrap property to False. To permit tabs in a memo, set the WantTabs property to True. The Alignment property determines how the text is aligned within the control. Possible choices are taLeftJustify (the default), taCenter, and taRightJustify. At run time, users can cut, copy, and paste text to and from a database memo control. You can accomplish the same task programmatically by using the CutToClipboard, CopyToClipboard, and PasteFromClipboard methods. Because the TDBMemo can display large amounts of data, it can take time to populate the display at run time. To reduce the time it takes scroll through data records, TDBMemo has an AutoDisplay property that controls whether the accessed data should automatically displayed. If you set AutoDisplay to False, TDBMemo displays the field name rather than actual data. Double-click inside the control to view the actual data.
Note
A TDBMemo control raises an exception if an attempt is made to access fields that contain more than 32K of data, or if edited data exceeds 32K in length.
By default, TDBImage permits a user to edit a graphics image by cutting and pasting to and from the Clipboard, or if you supply an editing method. You can accomplish the same task programmatically by using the CutToClipboard, CopyToClipboard, and
108
PasteFromClipboard methods. To make a TDBImage component read-only, set its ReadOnly property to True. Because the TDBImage can display large amounts of data, it can take time to populate the display at run time. To reduce the time it takes scroll through data records, TDBImage has an AutoDisplay property that controls whether the accessed data should automatically displayed. If you set AutoDisplay to False, TDBImage displays the field name rather than actual data. Double-click inside the control to view the actual data.
These components can be linked only to TTable components. They do not work with TQuery components. The following table describes these controls:
Table 4.5
TDBListBox TDBComboBox
Data control
TDBLookupList TDBLookupCombo
TDBComboBox
The TDBComboBox component is similar to a TDBEdit component, except that at run time it has a drop-down list that enables a user to pick from a predefined set of values. Here is an example of what a TDBComboBox component looks like at run time:
Figure 4.8 DBComboBox component
The Items property of the component specifies the items contained in the drop-down list. Use the String List Editor to specify the values for the drop-down list.
109
At run time, the user can choose an item from the list or (depending on the value of the Style property) type in a different entry. When the component is linked to a column through its DataField property, it displays the value in the current row, regardless of whether it appears in the Items list. The following properties determine how the Items list is displayed at run time: Style determines the display style of the component: csDropDown (default): Displays a drop-down list with an edit box in which the user can enter text. All items are strings and have the same height. csSimple: Displays the Items list at all times instead of in a drop-down list. All items are strings and have the same height. csDropDownList: Displays a drop-down list and edit box, but the user cannot enter or change values that are not in the drop-down list at run time. csOwnerDrawFixed and csOwnerDrawVariable: Allows the items list to display values other than strings (for example, bitmaps). For more information, see the online VCL reference. DropDownCount: the maximum number of items displayed in the list. If the number of Items is greater than DropDownCount, the user can scroll the list. If the number of Items is less than DropDownCount, the list will be just large enough to display all the Items. ItemHeight: The height of each item when style is csOwnerDrawFixed. Sorted: If True, then the Items list will be displayed in alphabetical order.
TDBListBox
TDBListBox is functionally the same as TDBComboBox, but instead of a drop-down list, it displays a scrollable list of available choices. When the user selects a value at run time, the component is assigned that value. Unlike TDBComboBox, the user cannot type in an entry that is not in the list. Here is an example of how a TDBListBox component appears at run time.
Figure 4.9 TDBListBox component
While navigating through a dataset, a TDBListBox component displays values in the column by highlighting the corresponding entry in its list. If the current rows value is not defined in the Items property, no value is highlighted in the TDBListBox. Changing the selection changes the underlying value in the database column and is equivalent to typing a value in a TDBEdit component. The IntegralHeight property controls the way the list box is displayed. If IntegralHeight is True (the default), the bottom of the list box moves up to the bottom of the last
110
completely-displayed item in the list. If IntegralHeight is False, the bottom of the list box is determined by the ItemHeight property, and the bottom item might not be completely displayed.
TDBLookupCombo
The TDBLookupCombo component is similar to TDBComboBox, except that it derives its list of values dynamically from a second dataset at run time, and it can display multiple columns in its drop-down list. With this control, you can ensure that users enter valid values into forms by providing an interface from which they can choose values. Here is an example of how a TDBLookupCombo component appears at run time:
Figure 4.10 TDBLookupCombo component
The lookup list for TDBLookupCombo must be derived from a second dataset. To display values from a column in the same table as the first dataset, drop a second data source and dataset component on the form and point them at the same data as the first data source and dataset. Three properties establish the lookup list for TDBLookupCombo, and determine how it is displayed: LookupSource specifies a second data source from where the control populates its list. LookupField specifies a field in the LookupSource dataset which links that dataset to the primary dataset. This must be a column in the dataset pointed to by LookupSource, and it must contain the same values as the column pointed to by the DataField property (although the column names do not have to match). LookupDisplay, if set, defines the columns that TDBLookupCombo displays. If you do not specify values in LookupDisplay, TDBLookupCombo displays the values found in the column specified by LookupField. Use this property to display a column other than that specified by LookupField, or to display multiple columns in the drop-down list. To specify multiple columns, separate the different column names with a semicolon. A TDBLookupCombo component appears similar to a TDBComboBox at both design time and run time, except when you want it to display multiple columns in its lookup list. How the control displays multiple columns depends on the Options property settings: loColLines: When True, uses lines to separate the columns displayed in the lookup list. loRowLines: When True, uses lines to separate the rows displayed in the lookup list. loTitles: When True, column names appear as titles above the columns displayed in the lookup list.
111
As a simple example, an order entry form could have a TDBLookupCombo component to specify the customer number of the customer placing the order. The user placing the order can simply click on the drop down pick list instead of having to remember the customer number. The value displayed could be the customer name. To build this form,
1 Choose File|New Project to create a new form. 2 Create a TDataSource component onto the form, then set its Name property to OrdSource. 3 Drop a TTable component on the form, and set the Name property to OrdTable, the DatabaseName property to DBDEMOS, the TableName property to ORDERS.DB, and the Active property to True. 4 Create a second TDataSource component on the form, then set its Name property to CustSource. 5 Create a second TTable component on the form, and set the Name property to CustTable, the DatabaseName property to DBDEMOS, the TableName property to CUSTOMER.DB, and the Active property to True. 6 Create a TDBGrid component and link it to OrdSource so it displays the contents of the ORDERS table. 7 Create a TDBLookupCombo component, and set its DataSource property to CustNo. The database lookup combo box is now linked to the CustNo column of the ORDERS table. 8 Specify the lookup values of the TDBLookupCombo component: Set LookupSource to CustSource (so it looks up values in the CUSTOMER table). Set LookupField to CustNo (so it looks up and gets values from the CustNo column). In LookupDisplay, type Company;Addr1 (this displays the corresponding company name and address in the drop-down list). 9 Set the loColLines and LoTitles properties (under the Option property) of the TDBLookupCombo to True.
At run time, the TDBLookupCombo component displays a drop-down list of company names and addresses. If the user selects a new company from the list, the control is assigned the value of the corresponding customer number (CustNo). When the user scrolls off the current order in the database grid, Delphi posts the new customer number and information to the row.
TDBLookupList
TDBLookupList is functionally the same as TDBLookupCombo, but instead of a drop-down list, it displays a scrollable list of the available choices. When the user selects one at run time, the component is assigned that value. Like TDBLookupCombo, the user cannot type in an entry that is not in the list. Here is an example of how a TDBLookupList component appears at run time:
112
While navigating through a dataset, a TDBLookupList component highlights the item in the list that corresponds to the value in the currently selected row. If the current rows value is not defined in the Items property, no value is highlighted in the TDBLookupList component. Changing the selection changes the underlying value in the database column and is equivalent to typing a value in a TDBEdit component.
TDBCheckBox
TDBCheckBox is a data-aware version of the Standard TCheckBox component. It can be used to set the values of fields in a dataset. For example, a customer invoice form might have a check box control that when checked, specifies that the customer is entitled to a special discount, or when unchecked means that the customer is not entitled to a discount
Figure 4.12 TDBCheckBox component
Like the other data controls, TDBCheckBox is attached to a specific field in a dataset through its DataSource and DataField properties. Use the Caption property to display a label for the check box on your form. Set the ValueChecked property to a value the control should post to the database if the control is checked when the user moves to another record. By default, this value is set to True, but you can make it any alphanumeric value appropriate to your needs. You can also enter a semicolon-delimited list of items as the value of ValueChecked. If any of the items matches the contents of that field in the current record, the check box is checked. For example, you can specify a ValueChecked string like:
DBCheckBox1.ValueChecked := 'True;Yes;On';
If the field for the current record contains values of True, Yes, or On, then the check box is checked. Comparison of the field to ValueChecked strings is case-insensitive. If a user checks a box for which there are multiple ValueChecked strings, the first string is the value that is posted to the database. Set the ValueUnchecked property to a value the control should post to the database if the control is not checked when the user moves to another record. By default, this value is set to False, but you can make it any alphanumeric value appropriate to your needs. You can also enter a semicolon-delimited list of items as the value of ValueUnchecked. If any of the items matches the contents of that field in the current record, the check box is unchecked. If the DataField of the check box is a logical field, the check box is always checked if the contents of the field is True, and it is unchecked if the contents of the field is False. In this
113
case, strings entered in the ValueChecked and ValueUnchecked properties have no effect on logical fields. A TDBCheckBox component is grayed out and disabled whenever the field for the current record does not contain one of the values listed in the ValueChecked or ValueUnchecked properties.
TDBRadioGroup
TDBRadioGroup is a data-aware version of the standard TRadioGroup component. It lets you set the value of a data field with a radio button control where there is a limited number of possible values for the field. The radio group consists of one button for each value a field can accept. TDBRadioGroup is attached to a specific field in a dataset through its DataSource and DataField properties. A radio button for each string value entered in the Items property is displayed on the form, and the string itself is displayed as a label to the right of the button.
Figure 4.13 A TDBRadioGroup component
For the current record, if the field associated with a radio group matches one of the strings in the Items or property, that radio button is selected. For example, if three strings, Red, Yellow, and Blue, are listed for Items, and the field for the current record contains the value Blue, then the third button in the group is selected.
Note
If the field does not match any strings in Items, a radio button may still be selected if the field matches a string in the Values property. If the field for the current record does not match any strings in Items or Values, no radio button is selected. The Values property can contain an optional list of strings that can be returned to the dataset when a user selects a radio button and posts a record. Strings are associated with buttons in numeric sequence. The first string is associated with the first button , the second string with the second button, and so on. For example, to continue the example for the three buttons labeled Red, Yellow, and Blue, if three strings, Magenta, Yellow, and Cyan, are listed for Values, and the user selects the first button (labeled Red), then Delphi posts Magenta to the database. If strings for Values are not provided, the label from a selected radio button (from Items) is returned to the database when a record is posted. Users can modify the value of a data field by clicking the appropriate radio button. When the user scrolls off the current row, Delphi posts the value indicated by the radio button string to the database.
114
Chapter
Chapter 5
SQL (Structured Query Language) is an industry-standard language for database operations. Delphi enables your application to use SQL syntax directly through the TQuery component. Delphi applications can use SQL to access data from: Paradox or dBASE tables, using local SQL. The allowable syntax is a sub-set of ANSIstandard SQL and includes basic SELECT, INSERT, UPDATE, and DELETE statements. For more information on local SQL syntax, see Appendix C, Using local SQL. Databases on the Local InterBase Server. Any statement in InterBase SQL is allowed. For information on syntax and limitations, see the InterBase Language Reference. Databases on remote database servers (Delphi Client/Server only). You must have installed the appropriate SQL Link. Any standard statement in the servers SQL is allowed. For information on SQL syntax and limitations, see your server documentation. Delphi also supports heterogeneous queries against more than one server or table type (for example, data from an Oracle table and a Paradox table). For more information, see Creating heterogenous queries on page 124.
Using TQuery
TQuery is a dataset component, and shares many characteristics with TTable, as described in Chapter 3, Using data access components and tools. In addition, TQuery enables Delphi applications to issue SQL statements to a database engine (either the BDE or a server SQL engine). The SQL statements can be either static or dynamic, that is, they can be set at design time or include parameters that vary at run time.
115
116
The following diagram illustrates the lifetime of a TQuery component and the methods used to work with it:
Figure 5.1 TQuery methods and flow
Set SQL text Prepare Set Parameters Unprepare Close Open ExecSQL
Fetch Data
Note
Prepare applies only to dynamic queries. It is not required, but is recommended in most cases. For more information, see Dynamic SQL statements on page 121.
A dynamic SQL statement, also called a parameterized statement, includes parameters for column or table names. For example, this is a dynamic SQL statement:
SELECT * FROM CUSTOMER WHERE CUST_NO = :Number
The variable Number, indicated by the leading colon, is a parameter which must be provided at run time and may vary each time the statement is executed.
117
Figure 5.2
Choose OK to assign the text you enter to the SQL property of the query. Choose Load to include text from a file or Save to save the text to a file. To specify SQL text at run time, an application should first close the query with Close and clear the SQL property with Clear. For example,
Query1.Close; {This closes the query} Query1.SQL.Clear; {This clears the contents of the SQL property}
It is always safe to call Closeif the query is already closed, the call will have no effect. Use the SQL propertys Add method to add the SQL statements to it. For example,
Query1.SQL.Add('SELECT * FROM COUNTRY'); Query1.SQL.Add('WHERE NAME = ''ARGENTINA''');
An application should always call Clear before specifying an SQL statement. Otherwise, Add will simply append the statements to the existing one.
Note
The SQL property may contain only one complete SQL statement at a time. In general, multiple statements are not allowed. Some servers support multiple statement batch syntax; if the server supports this, then such statements are allowed. You can also use the LoadFromFile method to assign the text in an SQL script file to the SQL property. For example,
Query1.SQL.LoadFromFile('C:\MYQUERY.TXT');
118
Figure 5.3
For information on how to use the Visual Query Builder, refer to its online Help. After you have you constructed a query and exited the Visual Query Builder, the SQL statement you constructed will be entered in the SQL property of the selected TQuery component.
Executing a query
At design time, you can execute a query by changing its Active property in the Object Inspector to True. The results of the query will be displayed in any data controls connected to the Query component (through a data source). At run time, an application can execute a query with either the Open or the ExecSQL methods. Use Open for SQL statements that return a result set (SELECT statements). Use ExecSQL for all other SQL statements (INSERT, UPDATE, DELETE, and so on). For example,
Query1.Open; {Returns a result set}
If the SQL statement does not return a cursor and a result set from the database, use ExecSQL instead of Open. For example,
Query1.ExecSQL; {Does not return a result set}
If you dont know at design time whether a query will return a result set, use a try...except block with Open in the try part and ExecSQL in the except part.
119
RequestLive
False TrueSELECT syntax meets requirements TrueSELECT syntax does not meet requirements
If an application needs to update the data in a read-only result set, it must use a separate TQuery to construct an UPDATE statement. By setting the parameters of the update query based on the data retrieved in the first query, the application can perform the desired update operation.
120
Does not have an ORDER BY clause. Does not use aggregates such as SUM or AVG. In addition, if the table is on a Sybase server, it must have a unique index.
Select the desired data type for the parameter in the Data Type combo box. Enter a value in the Value text field or select Null Value to set the parameters value to null. When you click OK, the query will be prepared and values will be bound to the parameters. Then, when you set the querys Active property to True, the results of the SQL query with the specified parameter values will be shown in any data controls connected to the query. At run time, an application can supply values to parameters with the following TQuery properties: The Params property, using the order that the parameters appear in the SQL statement. The ParamByName method, using the parameter names specified in the SQL statement. The DataSource property to set values from another dataset for columns that match the names of parameters that have no values.
Preparing a query
The Prepare method sends a parameterized query to the database engine for parsing and optimization. A call to Prepare is not required to use a parameterized query. However, it is strongly recommended, since it will improve performance for dynamic queries that
121
will be executed more than once. If a query is not explicitly prepared, each time it is executed, Delphi automatically prepares it. Prepare is a Boolean property of TQuery that indicates if a query has been prepared. The Parameters Editor automatically prepares a query when you use it to set parameter values at design time. If a query has been executed, an application must call Close before calling Prepare again. Generally, an application should call Prepare oncefor example, in the OnCreate event of the formthen set parameters using the Params property, and finally call Open or ExecSQL to execute the query. Each time the query is to be executed with different parameter values, an application must call Close, set the parameter values, and then execute the query with Open or ExecSQL. Preparing a query consumes some database resources, so it is good practice for an application to unprepare a query once it is done using it. The UnPrepare method unprepares a query. When you change the text of a query at run time, Delphi automatically closes and unprepares the query.
An application could use Params to specify the values of the parameters as follows:
Query2.Params[0].AsString := 'Lichtenstein'; Query2.Params[1].AsString := 'Vaduz'; Query2.Params[2].AsInteger := 420000;
These statements would bind the value Lichtenstein to the :Name parameter, Vaduz to the :Capital parameter, and 420000 to the :Population parameter.
122
Query2.ParamByName('Population').AsInteger := 420000;
These statements would have the same effect as the three previous statements that used the Params array directly.
As illustrated below, the form also contains: ATDataSource named OrdersSource, linked to Orders by its DataSet property. ATTable component (named Cust). ATDataSource named CustSource linked to Cust. Two data grids; one linked to CustSource and the other to OrdersSource.
Figure 5.5 Form with linked queries
Orders DataSource property is set to CustSource. Because the parameter :CustNo does not have any value assigned to it, at run time Delphi will try to match it with a column name in CustSource, which gets its data from the Customer table through Cust. Because there is a CustNo column in Cust, the current value of CustNo in the Cust table is assigned to the parameter, and the two data grids are linked in a master-detail relationship. Each time the Cust table moves to a different row, the Orders query automatically re-executes to retrieve all the orders for the current customer.
123
Provide parameters in response to some event. In this example, double-click on Button1 to edit the OnClick event and use the contents of Edit1.Text as a substitution parameter:
procedure TForm1.Button1Click(Sender: TObject); begin Query1.Close; Query1.Params[0].AsString := Edit1.Text; Query1.Open; end;
124
You can define BDE aliases with the BDE Configuration Utility, described in Appendix B, Using the BDE configuration utility. For example, suppose you define an alias called Oracle1 for an Oracle database that has a CUSTOMER table, and Sybase1 for a Sybase database that has an ORDERS table. A simple query against these two tables would be
SELECT CUSTOMER.CUSTNO, ORDERS. ORDERNO FROM :Oracle1:CUSTOMER, :Sybase1:ORDERS
125
126
Chapter
Chapter 6
Delphi Client/Server enables you to develop applications that can access remote SQL servers such as Oracle, Sybase, Informix, and InterBase, as well as local Paradox and dBASE databases. A remote server is one that is physically removed from the client machine on which the Delphi application runs. The server and client must be connected by a network. Delphi also includes the Local InterBase Server, a full-featured SQL server that runs on Microsoft Windows. There are a number of issues that are particularly important when developing a client/ server application: Portability versus optimization: Will the application use any server-specific SQL syntax? To what degree will the database be optimized for a particular server? Transactions: What kind of transaction control will the application require? Server features: Will the application require the use of server features such as stored procedures? How will these be surfaced? Connectivity: What communication protocol will the application use? Does the application need to be deployed to support multiple communication protocols? Deployment: What executables, libraries, and other files does the application require and how are these delivered to the end user?
127
Portability refers to the ease with which an database/application can run on different servers. Optimization refers to the extent to which an application takes advantage of the special features of a particular system. Client portability is not an issue with Delphi, because Delphi applications will run on any 16-bit or 32-bit Windows platform. However, server portability and communications portability can be considerations. Because Delphi applications use the Borland Database Engine, they can be easily integrated with dBASE and Paradox applications (for desktop data sources) and other clients for server data sources.
Server portability
It may be desirable to design an application so that it can be easily ported to different types of servers, either because the end-users require multiple heterogeneous server support, or because the application will be used by different groups of end-users with different types of servers. In designing a client-server application, there is an inherent trade-off between portability and optimization, because making use of server-specific features results in increased application performance but decreased portability. A Delphi application that uses only TTable components for data access will be fully portable among different server types. An application may benefit from improved performance by using TQuery components and passthrough SQL, and as long as the SQL syntax is ANSI standard, there will be little loss of portability. As soon as SQL syntax departs from the ANSI standard, the application will no longer be fully portable. If server portability is a consideration, you must carefully weigh whether the gain in using server-specific syntax is worth the cost in portability. Maintainability of an application may be reduced by optimization for a specific server type, because each server-specific implementation may require separate maintenance. An application can be further optimized by using server-specific features such as stored procedures. However, this will usually require server-specific implementation in the database, and perhaps the application, depending on how the features are surfaced. It is also important to consider that servers transaction processing may differ in subtle yet important ways. This and other distinctions among SQL servers may complicate portability. Before attempting to create a portable database/application, you should build an application that runs reliably against one type of server database. In some cases, it may be necessary to build the application separately against each of the target server types.
128
phase to ensure that the initial test deployment packages include the proper client communication software.
129
define a congruent database on the target server. Finally, you can redirect the application to access the database on the target server.
130
information on the BDE Configuration Utility, see Appendix B, Using the BDE configuration utility.
Connectivity
Delphi client applications can use any network protocol (such as TCP/IP or Novell SPX/IPX) supported by the server, as long as both the server and the client machines have the proper communication software installed. You must configure the SQL Link driver for the desired protocol. For more information, see the SQL Links for Windows Users Guide. Establishing an initial connection between client and server can often be problematic, especially when using TCP/IP, because there are a number of critical factors that must all be in place before a connection can be established.
Using TCP/IP
TCP/IP is a widely-used communication protocol that enables applications to connect to many different database servers. When using TCP/IP, you must ensure: The TCP/IP communication software and the proper Winsock driver are installed on the client. The servers IP address is registered in the clients HOSTS file or that Directory Network Services (DNS) is properly configured. The servers port number is entered in the clients SERVICES file. The application is searching the proper directory paths for the DLLs it needs. Check the PATH statement in AUTOEXEC.BAT. For more information, see the SQL Links for Windows Users Guide and your server documentation.
Connection parameters
The Params property of a connected TDatabase object contains a TString list of all the SQL Link parameters required to connect to a server of the specified type. You can edit these parameters by clicking on the ellipsis button to the right of the Params property in the Object Inspector. The String List Editor opens with the parameters For example, here are the parameters for connection to an InterBase server:
131
Figure 6.1
You can modify these parameters and add others as needed to customize the connection performed by the application. For more information, see the SQL Links for Windows Users Guide.
Using ODBC
A Delphi application can access ODBC data sources such as DB2, Btrieve, or Microsoft Access through the Borland Database Engine (BDE). To do this, you must set up an ODBC driver connection using the BDE Configuration Utility. An ODBC driver connection requires: A vendor-supplied ODBC driver. The Microsoft ODBC Driver Manager. A BDE alias, established with the BDE Configuration Utility or with Delphi. The BDE configuration setting AUTO ODBC (on the System page) enables an alias to automatically configure for use of ODBC. When AUTO ODBC is True, datasource and driver information will automatically be imported from the ODBC.INI file. For more information, see the online help for the BDE Configuration Utility.
132
Figure 6.2
A Delphi application can handle server login several different ways: If the LoginPrompt property of a TDatabase component is True (the default), the standard Delphi Login dialog box will be opened when the application attempts to establish a database connection. By setting LoginPrompt to False, and including the USERNAME and PASSWORD parameters in the Params property of the TDatabase component. For example,
USERNAME = SYSDBA PASSWORD = masterkey
This is generally not recommended since it compromises server security. Use the OnLogin event of TDatabase to set login parameters. The OnLogin event gets a copy of the TDatabase's login parameters array. Use the Values property to change these parameters:
LoginParams.Values['SERVER NAME'] := 'MYSERVERNAME'; LoginParams.Values['USER NAME'] := 'MYUSERNAME'; LoginParams.Values['PASSWORD'] := 'MYPASSWORD';
When control returns from your DatabaseLogin event handler, these parameters will be used to establish a connection.
The DataSets property of TDatabase is an array of pointers to the active datasets in the TDatabase. The DatasetsCount property is an integer that specifies the number of active datasets.
133
This tool enables you to customize application-specific aliases local based on existing aliases. The three text fields at the top of the dialog box correspond to the DatabaseName, AliasName, and DriverName properties.
134
DatabaseName is the name of the database connection that can be used by dataset components instead of a BDE alias, directory path, or database name. In other words, this is the name of the local alias defined by the component that will show up in the DatabaseName drop-down list of dataset components. AliasName is the name of an existing BDE alias configured with the BDE Configuration Utility. This is where the component gets its default parameter settings. This property will be cleared if DriverName is set. DriverName is the name of a BDE driver, such as STANDARD (for dBASE and Paradox), ORACLE, SYBASE, INFORMIX or INTERBASE. This property will be cleared if AliasName is set, because an AliasName specifies a driver type. Choose the Defaults button to retrieve the default parameters for the selected alias. The values will be displayed in the Parameters list box. Any changes you make to the defaults are used instead of the default values for any database connection in the application that uses that DatabaseName. The check boxes labeled Loginprompt and Keep inactive connection correspond to the LoginPrompt and KeepConnections properties of the TDatabase component.
135
Explicitly: depending on the level of control the application requires, either with The StartTransaction, Commit, and Rollback methods of TDatabase. This is the recommended approach. Passthrough SQL in a TQuery component. The application must use serverspecific SQL transaction control statements. You must understand how your server performs transaction handling. Transaction control statements are only meaningful when the database is on an SQL server. The StartTrans, Commit, and Rollback methods will raise an exception if the underlying database is Paradox or dBASE.
136
translates to whether passthrough transactions and other transactions know about each other. Only applications that use passthrough SQL need be concerned with SQLPASSTHRUMODE. SQLPASSTHRUMODE can have the following settings: SHARED AUTOCOMMIT (the default) SHARED NOAUTOCOMMIT NOT SHARED With SHARED AUTOCOMMIT, each operation on a single row is committed. This mode most closely approximates desktop database behavior, but is inefficient on SQL servers because it starts and commits a new transaction for each row, resulting in a heavy load of network traffic. With SHARED NOAUTOCOMMIT, the application must explicitly start and commit transactions. This setting can result in conflicts in busy, multiuser environments where many users are updating the same rows. NOT SHARED means that passthrough SQL and Delphi methods use separate database connections.
Note
To control transactions with passthrough SQL, you must set SQLPASSTHRU MODE to NOT SHARED. Otherwise, passthrough SQL and Delphis methods may interfere with each other, leading to unpredictable results.
137
Table 6.1, Server transaction isolation levels. For a detailed description of how each isolation level is implemented, see your server documentation.
Table 6.1 Server transaction isolation levels
Sybase and Microsoft SQL servers
Read committed Read committed Read committed
TransIsolation setting
Dirty read Read committed (Default) Repeatable read
Oracle
Read committed Read committed Repeatable read (READ ONLY)
Informix
Dirty Read Read committed Repeatable Read
InterBase
Read committed Read committed Repeatable Read
If an application is using ODBC to interface with a server, the ODBC driver must also support the isolation level. For more information, see your ODBC driver documentation.
InterBase select procedures are called with the SELECT statement as if querying a table. To get output from such procedures, use a TQuery component with the appropriate SELECT syntax.
138
Figure 6.4
The Parameters Editor displays the input and output parameters for the procedure. To prepare the stored procedure with the default parameter types and field types, simply choose OK. You can set values of input parameters at design time by choosing the parameter in the Parameters list and entering a value in the Value field. To specify null input parameter values, select the Null value check box. The Parameters Editor is explained in more detail in Chapter 5, Using SQL in applications.
Note
Delphi will attempt to get information on input and output parameters from the server. For some servers (such as Sybase), this information may not be accessible. In such cases, you must enter the names and data types of the input and output parameters in the Parameters Editor at design time.
To execute a prepared stored procedure, use the ExecProc method. Values can be assigned to and from a TStoredProc component just as for TQuery components, by using the Params array. For example, the following code could be in a buttons OnClick event:
StoredProc1.Params[0].AsString := Edit1.Text; StoredProc1.ExecProc; Edit2.Text := StoredProc1.Params[1].AsString;
The first parameter, Params[0], is an input parameter of type String. It is assigned the text entered by the user in Edit1. Then, assuming StoredProc1 has been prepared at design time with the Parameters Editor, the stored procedure is run with ExecProc. Finally, the output parameter, Params[1], is displayed by Edit2. On some servers, stored procedures can return a result set similar to a query. Applications can use data aware controls to display the output of such stored procedures. You do this in the same way as you display output from TQuery
139
components: create a TDataSource component and assign its name to a data grids DataSource property.
Upsizing
Migrating a desktop application to a client/server application is called upsizing. Upsizing is a complex topic and a full treatment of it is beyond the scope of this book. However, this section will address some of the most important aspects of upsizing a Delphi application. Upsizing has two major facets: Upsizing the database from the desktop to the server Upsizing the application to address client/server considerations Upsizing requires a shift in perspective from the desktop world to the client/server world. Desktop databases and SQL server databases are different in many respects. Desktop databases are designed for one user at a time, while servers are designed for multiuser access. Desktop databases are conceptually record-oriented, while server databases are conceptually set-oriented. Desktop databases typically store each table in a separate file, while servers store all the tables in a database together. Client/server applications must also address some entirely new issues, the most complex of which are connectivity, network usage, and transaction handling.
140
Use the Database Desktop utility and choose Tools|Utilities|Copy to copy a table from desktop table to SQL format. For more information, see Appendix A, Using Database Desktop. Build a Delphi application that uses a TBatchMove component. For more information on TBatchMove, see Chapter 3, Using data access components and tools. Both of these options will copy table structures and migrate data from the desktop source to the server destination. Depending on the database, it may be necessary to make changes to the tables created by these methods. For example, the datatype mappings may not be exactly as desired. Additionally, you must add to the database any of the following features if required: Integrity constraints (primary and foreign keys) Indexes Check constraints Stored procedures and triggers Other server-specific features
Depending on the database, it may be most efficient to define the metadata first by using an SQL script and the servers data definition tools and then migrate the data using one of the two methods previously mentioned. If you define the table structure manually, then Database Desktop and TBatchMove will copy only the data.
141
be performed on the server, so the application would only retrieve the answer from the server.
For more information on deploying Delphi applications, refer to the file DEPLOY.TXT, installed to the DELPHI\DOC directory by default. Each server type has a set of files for the SQL Link. In addition, a file used by all the SQL Links is BLROM800.LD, the Roman8 language driver using binary collation sequence.
Oracle
The following files provide the SQL Links interface with Oracle servers. In addition, applications will require Oracle client files for interface to low-level communication protocols such as TCP/IP. Refer to your server documentation.
Table 6.2
File name
SQLD_ORA.DLL SQLD_ORA.HLP SQL_ORA.CNF ORA6WIN.DLL ORA7WIN.DLL SQL13WIN.DLL SQLWIN.DLL COREWIN.DLL ORAWE850.LD
142
Table 6.3
File name
Informix
The following files provide the SQL Links interface with Informix servers. In addition, applications will require Informix client files for interface to low-level communication protocols such as TCP/IP. Refer to your server documentation.
Table 6.4
File name
SQLD_INF.DLL SQLD_INF.HLP SQL_INF.CNF LDLLSQLW.DLL ISAM.IEM OS.IEM RDS.IEM SECURITY.IEM SQL.IEM
InterBase
The following files provide the SQL Links interface to remote InterBase servers. These files are distinct from those required to access the Local InterBase Server..
Table 6.5
File name
SQLD_IB.DLL SQLD_IB.HLP SQL_IB.CNF CONNECT.EXE CONNECT.HLP GDS.DLL REMOTE.DLL INTERBAS.MSG
143
TCP/IP Interface
The following files provide InterBase client applications their interface to Winsock 1.1 compliant TCP/IP products.
Table 6.6
File name
MVWASYNC.EXE VSL.INI WINSOCK.DLL MSOCKLIB.DLL
For TCP/IP products that are not Winsock 1.1 compliant, InterBase client applications will require one of the following files. During installation, Delphi will prompt you to select the TCP/IP stack for which to install support. If the deployed application needs to support a different TCP/IP stack, you must copy the corresponding file from the installation disks.
Table 6.7
File name
M3OPEN.EXE
M3OPEN.DLL MBW.EXE MFTP.EXE MHPARPA.DLL MNETONE.EXE MNOVLWP.DLL MPATHWAY.DLL MPCNFS.EXE MPCNFS2.EXE MPCNFS4.DLL MWINTCP.EXE
144
For more information on deploying ReportSmith reports, refer to the file DEPLOY.TXT, installed to the DELPHI\DOC directory by default.
145
146
Appendix
A
Appendix A
This appendix describes Database Desktop and provides a synopsis of Database Desktop features. The complete Database Desktop Users Guide is available on the Delphi CD-ROM, and all features are described in Database Desktop Help.
147
Status line
Files you open in Database Desktop appear in their own type of windows. Tables appear in Table windows, queries appear in Query windows, and SQL statements appear in the SQL Editor. Below the menu is a tool bar. The tool bar changes when the active window changes. The following figure shows the application window tool bar.
Figure A.2
Open Table
Managing files
In Database Desktop you work with three types of files: QBE queries, .SQL files, and tables. Other files are created automatically by Database Desktop. For a list of file extensions used by Database Desktop, search for file-name extensions in the keyword list in Database Desktop Help, and choose the topic Types of Files.
Opening files
To open a QBE query, SQL statement, or table, follow these steps:
1 Choose File|Open. 2 Choose the type of file to openQBE query, SQL statement, or table.
148
To access tables stored on a network, you must specify the location of the network control file. You do this by running the BDE Configuration Utility; double-click the BDE Configuration Utility icon in the Delphi program group. See online Help in the BDE Configuration Utility for more details.
Aliases
You can assign an alias as a shorthand for a directory using the Alias Manager dialog box. For example, if you have a collection of tables and queries in one directory (called C:\DBD\PROJECTS\CUSTLIST), you can specify the alias :MYWORK: rather than type the entire path. Using aliases, you can avoid typing long path names, and you can use the Path list in File|Open and File|Save dialog boxes to list files in any directory for which you have defined an alias. To create an alias, choose File|Aliases. For information on creating, changing, or removing an alias, search for aliases in the keyword list in Database Desktop Help.
Creating tables
This section describes tables and discusses how to create and restructure Paradox, dBASE, and SQL tables in Database Desktop.
149
Understanding tables
A database is an organized collection of information or data. An address book is an example of a database. It organizes data about people into specific categories: names, phone numbers, and addresses. In a relational database, the data is organized into tables. Each row of a table contains information about a particular item; this is called a record. Each column contains one piece of the information that makes up a record; this is called a field.
Figure A.3 A table
This row is one record. It contains one value for each field.
This column is one field. It contains one kind of information about a record.
Relational tables
Relational database applications such as dBASE and Paradox give you a way to link tables by comparing values stored in comparable fields in separate tables. The advantage of a relational database is that you can easily extract or combine data from several tables to get exactly the information you need, without changing the structure of the database. Also, a few small and discrete tables are more convenient to use and maintain than one large table. The sample database files CUSTOMER.DB and BOOKORD.DB are examples of relational tables. These tables can be linked through the fields containing customers ID numbers (Cust ID in the Customer table, Cust in Bookord). When the tables are linked, you can extract information from both tables into one table. For example, you can search for and extract a list of quantities ordered (from the Bookord table) and the respective last names (from Customer). The results are returned in an Answer table (see page 170).
Planning tables
Planning is the first step in creating a table. Decide what you want the table to contain and how you want to lay it out. For tips on planning tables, search for planning in the keyword list in Database Desktop Help, and choose the topic Planning Tables.
150
1 Choose File|New|Table. Or right-click the Open Table tool bar button, and choose New.
The Table Type dialog box appears.
Figure A.4 Table Type dialog box
Choose the type of table you want to create. Some options discussed in this appendix are available only to Paradox for Windows 5.0 tables.
2 If you want a table type other than Paradox for Windows, click the arrow next to the list box and select from the drop-down list. 3 Choose OK. The Create Table dialog box appears. This dialog box may have a slightly different appearance for different table types, but it will function the same.
Figure A.5 The Create Table dialog box
Press any key or doubleclick to key the table. When the dialog box is opened, the Validity Checks table property is selected and all types of validity checks are available. Enter the field name, type, and size in the Field Roster.
The status box gives you guidelines as you create the table.
For a step-by-step description of creating a table, search for creating tables in the keyword list in Database Desktop Help, and choose the topic Creating a New Table.
151
Defining fields
Use the Field Roster in the Create Table dialog box (page 151) to define the fields of the new table. You can use the mouse, arrow keys, Enter, Tab, or Shift+Tab to move among the columns. (Shift+Tab moves backwards.)
Field names
Type field names in the Field Name column of the Field Roster. For information on rules governing field names, search for field names in the keyword list in Database Desktop Help, and choose the topic for the type of table you are using (Paradox, dBASE, or SQL).
1 Select the Type column of the field you want. 2 Type the symbol (or name, for SQL tables) for the field type or select from the dropdown list. You can use the list in two ways: Right-click the Type column again and click to select the field type. Press Spacebar to see the list, then choose the field type.
For information on field types and sizes, search for field types in the keyword list in Database Desktop Help, and choose the topic for the type of table you are using (Paradox, dBASE, or SQL).
Using indexes
The BDE uses indexes to keep track of the location of records in tables. This makes it easy to maintain a sorted order of a table and view like values together. When you create an index for a Paradox or dBASE table, Database Desktop creates a file that contains the indexed fields values and their locations. Database Desktop uses the index file to locate and sort the records in a table. Indexes work differently for Paradox, dBASE, and SQL tables.
152
values (taken as an ordered group) must be unique. This guards against duplication of data within the table. Keys are required for linking tables and for using the data integrity features of Paradox tables. To create a key, display the Create Table (page 151) or the Restructure Table (page 160) dialog box. Then move to the Key column in the Field Roster and double-click (or press any key). The key field indicator (*) appears. Database Desktop keys the table on the selected field. Follow these rules when defining keys: A table can have only one primary key. This key can be made up of one or more fields. If a key is defined as a single field, that field must be the first field in the Field Roster. If you identify more than one field as keyed, you create a composite key. These fields, taken as a group, must be unique for each record of the table. The composite key must be the first fields in the Field Roster.
Delphi does not support all dBASE index types. For more information, see Chapter 3, Using data access components and tools.
153
insert, depending on the server. To add a unique index to an existing table, choose Utilities|Restructure. For more information on SQL indexes, see Creating indexes on SQL tables on page 155.
Validity checks work only on Paradox tables, not on dBASE tables. For SQL tables, the only validity check you can specify in Database Desktop is whether a field is required (not Null).
Table A.1 Paradox validity checks
Meaning
Every record in the table must have a value in this field. SQL tables can also use this validity check (equivalent to NOT NULL). The values entered in this field must be equal to or greater than the minimum you specify here. The values entered in this field must be less than or equal to the maximum you specify here. The value you specify here is automatically entered in this field. You can replace it with another value. You specify a character string that acts as a template for the values that can be entered in this field. The values entered in this field are automatically formatted according to this picture. For information on pictures, search for picture strings in the keyword list in Database Desktop Help, and choose the topic Picture String Characters.
Validity check
Required field Minimum Maximum Default Picture
For detailed information on validity checks, search for validity checks in the keyword list in Database Desktop Help.
Note
A Required field validity check will set a Delphi TFields Required property to True when the table is accessed from a Delphi application.
154
Check to make the selected field a required field Choose these to create, modify, or delete an index from the SQL table
For information on valid field types for your SQL server, search for field types in the keyword list in Database Desktop Help, and choose the topic for your server.
155
Figure A.7
When you use an SQL table in Database Desktop, the table should have a unique index. If it does not have a unique index, you may not be able to view new records you insert. For detailed information on using the Define Index dialog box, search for Define Index Dialog Box in the keyword list in Database Desktop Help, and choose the topic Define Index Dialog Box (SQL Tables).
Sybase index names need only be unique within a table, not within the entire database, so Database Desktop does not prefix Sybase index names with table names. When you create an SQL index and choose OK from the Define Index dialog box, Database Desktop supplies the prefix <table>_ for the index name as follows:
Figure A.8 Save Index As dialog box
You can include the table name with the index name or omit it: If you type the index name following <table>_, Database Desktop prefixes the index name with the table name and an underscore. If you delete <table>_, Database Desktop omits the table name from the index name. If the index name is not unique, an error will occur when Database Desktop saves the table.
156
This index naming scheme also affects restructuring , as described in Restructuring an SQL table on page 160.
ORDERS
OrderNo CustomerNo
Name
Database Desktop accepts only those values that exist in the parent tables key as valid values for the specified field(s) of the child table. You can establish referential integrity only between like fields that contain matching values. For example, you can establish referential integrity between Customer and Orders on their CustomerNo fields. In both cases, the values contained in the specified fields are the same. The field names dont matter as long as the field types and sizes are identical.
Note
You can establish referential integrity only between tables in the same directory. Using referential integrity, Database Desktop checks the validity of a value before accepting it in the table. If you establish referential integrity between Customer and Orders on their CustomerNo fields, then enter a value in the CustomerNo field of Orders, Database Desktop searches the CustomerNo field of Customer and Accepts the value in Orders if it exists in Customer Rejects the value in Orders if it doesnt exist in Customer
Procedure
To define a referential integrity relationship,
1 In the Create Table (page 151) or Restructure Table (page 160) dialog box, choose Referential Integrity from the Table Properties list. The Define button becomes available.
157
Choose the parent table whose key you want to refer to.
3 Choose the parent table from the Table list. The tables key field appears in the Parents Key area of the referential integrity diagram. 4 Double-click the child tables field in the Fields list (or Tab to it and click the Add Field arrow or press Alt+A). The field name appears in the Child Fields area of the referential integrity diagram. 5 Choose the update rule you want. 6 Choose whether you want to enforce strict referential integrity. 7 Choose OK to name and save the referential integrity relationship.
For detailed information on defining referential integrity, search for Referential Integrity or Referential Integrity Dialog Box in the keyword list in Database Desktop Help.
158
For detailed information on table lookup, search for table lookup in the keyword list in Database Desktop Help, and choose the topic Looking up Table Values.
Note
Restructuring tables
Database Desktop enables you to restructure Paradox and dBASE tables to: Add or rename fields Change field types or sizes Modify indexes Modify table language drivers
Restructuring a table is very much like creating it for the first time. You will not be able to restructure a table if Delphi or any other application has the table open. For detailed information on restructuring tables, see the Database Desktop Help; choose Help| Contents|Tasks|Creating and Restructuring|Restructuring a Table.
Note
Restructuring a table may require corresponding modifications in Delphi applications that access the table. For example, removing a column or changing its data type will raise an exception if an application has a persistent TField component for the modified column. To restructure a table, choose Utilities|Restructure, then choose the table you want. If the table you want to restructure is already open in the active window, use Table| Restructure. The Restructure Table dialog box opens. The following figure shows an example of a Paradox table in the Restructure Table dialog box:
159
Figure A.11 The Restructure Table dialog box for Paradox tables
Work in the Restructure Table dialog box the same way you work in the Create Table dialog box.
Pack a table to reuse disk space left over from deleting records. Some restructure operations automatically pack your table. You can check Pack Table and choose OK when you want to be sure Paradox packs the table.
Choose these to create, modify, or delete an index from the SQL table
160
If you create a new index during a restructure, Database Desktop prompts you to prefix the index name with the table name. If you modify an index during a restructure, Database Desktop does not modify the index name, unless you rename the index as part of your modification. If you choose Save As during a restructure, Database Desktop prefixes all index names with the new table name, if you have not explicitly entered an index name. For example, suppose the EMPLOYEE table contains the following indexes: EMPLOYEE_DEPT_NO EMPLOYEE_EMP_NO FULL_NAME JOB If you restructure the table and save it as MY_DEPT, Database Desktop renames the indexes as follows: MY_DEPT_DEPT_NO MY_DEPT_EMP_NO MY_DEPT_FULL_NAME MY_DEPT_JOB
Viewing tables
To open a table, choose File|Open|Table. Or, if the application window is empty, click the Open Table button in the tool bar. In the Open Table dialog box, choose the table to open. The table you chose opens in a Table window, and the tool bar appears as shown in the following figure:
Figure A.13 The Table window tool bar
Copy Restructure Previous Set Next Record Last Record Edit Data
Cut
Paste
First Record
Previous Record
Next Set
Field View
When you first open a table, its data appears in a Table window in View mode. Each Table window contains an independent view of a table, so different views of a single table can be open at the same time. Up to 24 tables can be open at one time. To be able to simultaneously access tables stored on a network, you must provide Database Desktop the location of the network control file. You do this by running the BDE Configuration Utility; double-click the BDE Configuration Utility icon in the Delphi program group. See online Help in the BDE Configuration Utility for more details. A Delphi application can specify the network control file in the NetFileDir property of TSession. This enables a Delphi application access to tables stored on a network.
161
When you position the pointer over the scroll lock triangle, it changes to a double-headed arrow. After you release the mouse button, an active scroll lock appears.
162
To change the heading height, drag the table name up or down. The pointer when changing the column width
To change the row height, drag this line up or down. The pointer when moving a column
To resize a column, drag its right grid line in its top row.
Resizing rows
To resize the height of all of the rows in a table, drag the line under the first record number. Move the line up to decrease the row height, or down to increase the row height.
163
For detailed information on the Properties menu commands, search for Properties menu in the keyword list in Database Desktop Help.
Editing data
This section introduces Database Desktops editing features. For detailed information on editing data, search for editing data or Edit mode in the keyword list in Database Desktop Help.
In Database Desktop you cannot edit data in the following field types: Paradox: Memo, Formatted Memo, Graphic, OLE, Autoincrement, Binary, or Bytes dBASE: Memo, OLE, or Binary SQL: any BLOB (binary large object) field or a text field that allows more than 255 characters
Figure A.16 The Customer table in Edit mode
164
Field view
In Edit mode, you can change a fields entry in one of two ways: Select the field and type a new value. When you begin typing, the new value replaces the old entry. Select the field and edit the existing entry using field view. For information on field view, search for Field View in the keyword list in Database Desktop Help.
You cannot use an SQL table as the source of a Subtract operation. Empty: Use the Empty utility to remove all records from a table, leaving the tables structure (including all keys, indexes, validity checks, and so on) intact. You can use Empty on Paradox, dBASE, and SQL tables. Choose Utilities|Empty. Database Desktop opens the Empty dialog box. For detailed information on emptying tables, see Database Desktop Help; choose Help|Contents|Tasks|Using Table Utilities|Emptying Tables.
165
Sorting tables
When you sort a table, you tell Database Desktop to rearrange the order of the records in the table and display them in the order you specify. If a table is keyed, Database Desktop creates a new, unkeyed table containing the sorted data. The original table remains unchanged. If a table is not keyed, the sort changes the actual location of the records in the table.
SQL
You cannot sort SQL tables. To sort a table, choose Utilities|Sort, then choose the table you want to sort from the Select File dialog box. Database Desktop opens the Sort Table dialog box. For detailed information on sorting tables, see Database Desktop Help; choose Help| Contents|Tasks|Using Table Utilities|Sorting Tables.
Copying objects
You can copy Paradox and dBASE tables, queries, SQL tables, and .SQL files from within Database Desktop. To copy an object, choose Utilities|Copy. Database Desktop opens the Copy dialog box. When you copy a table, Database Desktop copies both the structure of the table and the data contained in it. You can copy tables from one table type to another. For example, you can copy a Paradox table to a dBASE or SQL table. To copy to an SQL table type, you must have an SQL database server and the appropriate SQL Link. For detailed information on copying objects, see Database Desktop Help; choose Help| Contents|Tasks|Using Table Utilities|Copying Tables.
Renaming objects
You can rename tables, queries, and .SQL files from within Database Desktop. You cannot rename SQL tables. To rename an object, choose Utilities|Rename. Database Desktop opens the Rename dialog box. For detailed information on renaming objects, see Database Desktop Help; choose Help|Contents|Tasks|Using Table Utilities|Renaming Tables.
Deleting objects
You can delete tables, queries, SQL tables, and .SQL files from within Database Desktop.
166
To delete an object, choose Utilities|Delete. Database Desktop opens the Delete dialog box. For detailed information on deleting objects, see Database Desktop Help; choose Help|Contents|Tasks|Using Table Utilities|Deleting Tables.
If you execute a SELECT statement in the SQL Editor, Database Desktop displays the resulting data in an Answer table, as shown in Figure A.18.
167
The SQL Editor has the tool bar shown in Figure A.19.
Figure A.19 SQL Editor Toolbar
Copy Run SQL Search Next Answer Table Options
Cut
Paste
Search
Select Alias
Do this
Choose File|New|SQL Statement Or right-click the Open SQL Script tool bar button and choose New Choose File|Open|SQL Statement Or click the Open SQL Script tool bar button Or right-click the Open SQL Script tool bar button and choose Open Choose Query|Show SQL Or click the Open SQL Script tool bar button
Specifying an alias
Before running an SQL statement, you must specify the alias that the statement will run against. To specify an alias, do one of the following: Choose SQL|Select Alias. Click the Select Alias tool bar button. Database Desktop opens the Select Alias dialog box, where you can choose one of the aliases you created in the Alias Manager dialog box. You cannot include an alias in the text of the SQL statement.
168
If your SQL statement is a query, the query results are displayed in an Answer table, as shown in Figure A.18 on page 168.
169
The Answer table displays the checked fields for records that match the example.
The result of a query is a temporary table called Answer. The Answer table is overwritten each time a query is run.
SQL
If you have Borland SQL Links, you can use QBE to view and query tables on SQL servers. For more information, see the Database Desktop Help Contents. For details on using QBE, see Database Desktop Help; choose Help|Contents|Tasks| Using Query-By-Example.
170
Appendix
B
Appendix B
The Borland Database Engine configuration utility (BDECFG.EXE) enables you to configure BDE aliases and change the settings reflecting your specific environment in the BDE configuration file, IDAPI.CFG. To run the BDE Configuration Utility, double-click the BDE configuration utility icon in the Delphi program group. The BDE Configuration Utility opens:
Figure B.1 BDE Configuration Utility main window
171
1 Select the Alias Manager (Aliases page) and choose the New Alias button. The Add New Alias dialog box appears. The type can be STANDARD or SQL-specific.
Figure B.2 Sample Add New Alias dialog box
2 Enter the new alias name and select the SQL-specific alias type. Then choose OK to begin the setup process. The Alias Manager displays all the configuration parameters you can change to customize the new alias.
Figure B.3 Customizing the new alias
3 If desired, edit the settings for the category you selected. If you leave any categories blank, the Alias Manager assumes you want to use the default for driver type. 4 When you are finished, select File|Save to save the new alias in the default configuration file; select File|Save as to save the new alias in a configuration file with a different name.
172
Note
The other pages contain settings that can also be customized. See online help for specifics.
Page
Driver Manager System Manager Date Manager Time Manager Number Manager
Settings modified
Those BDE uses to determine how an application creates, sorts, and handles tables. Those BDE uses to start an application. Those used to convert string values into date values. Those used to convert string values into time values. Those used to convert string values to number values.
If you save the new alias in a configuration file with a different name, the BDE Configuration Utility displays:
Figure B.4 BDE non-system configuration dialog box
Choose Yes if you want to activate this configuration file next time you start your application. Choose No if you want to keep using the current default configuration file. Your changes take effect the next time you start your application.
1 Scan the list of Alias Names available through the current configuration file. If the alias you want to modify was stored in a different configuration file, use File|Open to load that configuration file. 2 Highlight the name of the alias you want to modify. The configuration for that alias appears in the Parameters section of the Alias Manager page. 3 Highlight the configuration parameter you want to change, and enter the desired value. If you leave any categories blank, the Alias Manager assumes you want to use the drivers default value. 4 When you are finished, select File|Save to save the new alias in the default configuration file; select File|Save As to save the new alias in a configuration file with a different name.
When you modify a driver parameter, all aliases that use the default setting for that parameter inherit the new setting. Your changes take effect the next time you start your application.
173
Deleting an alias
To delete an alias,
1 Scan the list of Alias Names available through the current configuration file. If the alias you want to delete was stored in a different configuration file, use File|Open to load that configuration file. 2 Highlight the name of the alias you want to modify, and select the Delete Alias button. 3 Select File|Save to save your changes in the default configuration file; select File| Save As to save your changes in a different configuration file.
Note
If an application attempts to use an alias that has been deleted, Delphi will raise an exception. If a Delphi form was saved with a table or query open, Delphi will attempt to open the dataset when the form is loaded and the exception will occur at that time. In many cases, modifying an alias can also cause an exception in Delphi forms if the changes to the alias require changes to the Delphi application.
174
Appendix
C
Appendix C
The BDE enables limited access to database tables through local SQL (also called clientbased SQL). Local SQL is a subset of ANSI-standard SQL enhanced to support Paradox and dBASE naming conventions for tables and fields (called columns in SQL). Two categories of SQL statements are supported: Data Manipulation Language (DML) for selecting, inserting, updating, and deleting table data. Data Definition Language (DDL) for creating, altering, and dropping tables, and for creating and dropping indexes. This appendix describes naming conventions, syntax enhancements, and syntax limitations for local SQL. For a complete introduction to ANSI-standard SQL, see one of the many third-party books available at your local computer book store.
Local SQL also supports BDE aliases for table names. For example,
SELECT * FROM :PDOX:TABLE1
Finally, local SQL permits table names to duplicate SQL keywords as long as those table names are enclosed in single or double quotes. For example,
SELECT PASSID FROM "PASSWORD"
175
In the next example, the column name duplicates the SQL DATE keyword:
SELECT DATELOG."DATE" FROM DATELOG
Data manipulation
With some restrictions, local SQL supports the following statements for data manipulation: SELECT, for retrieving existing data INSERT, for adding new data to a table UPDATE, for modifying existing data DELETE, for removing existing data from a table The following sections describe parameter substitution, aggregate, string, and date functions, and operators available to DML statements in local SQL.
176
MAX(), for determining the maximum value in a column COUNT(), for counting the number of values in a column that match specified criteria
Note
For example, the following statement extracts the year value from a DATE field:
SELECT EXTRACT(YEAR FROM HIRE_DATE) FROM EMPLOYEE
You can also extract MONTH, DAY, HOUR, MINUTE, and SECOND using this function.
Note
Supported operators
Local SQL supports the following arithmetic operators:
+, , *, /
177
Using SELECT
The SELECT statement is used to retrieve data from one or more tables. A SELECT that retrieves data from multiple tables is called a join. Local SQL supports the following form of the SELECT statement:
SELECT [DISTINCT] column_list FROM table_reference [WHERE search_condition] [ORDER BY order_list] [GROUP BY group_list] [HAVING having_condition]
Except as noted below, all clauses are handled as in ANSI-standard SQL. Clauses in square brackets are optional. The column_list indicates the columns from which to retrieve data. For example, the following statement retrieves data from two columns:
SELECT PART_NO, PART_NAME FROM PARTS
The WHERE clause can now include the IN predicate, followed by a parenthesized list of values. For example, the next statement retrieves only those rows where a part number matches an item in the IN predicate list:
SELECT * FROM PARTS WHERE PART_NO IN (543, 544, 546, 547)
Important
178
The next query retrieves all part information ordered in descending numeric order by part number:
SELECT * FROM PARTS ORDER BY PART_NO DESC
Calculated fields can be ordered by correlation name or ordinal position. For example, the following query orders rows by FULL_NAME, a calculated field:
SELECT LAST_NAME || ', ' || FIRST_NAME AS FULL_NAME, PHONE FROM CUSTOMERS ORDER BY FULL_NAME
Heterogeneous joins
Local SQL supports joins of tables in different database formats; such a join is called a heterogeneous join. For example, it is possible to retrieve data from a Paradox table and a dBASE table as follows:
SELECT DISTINCT C.CUST_NO, C.STATE, O.ORDER_NO FROM "CUSTOMER.DB" C, "ORDER.DBF" O WHERE C.CUST_NO = O.CUST_NO
Using INSERT
In local SQL, INSERT is restricted to a list of values:
INSERT INTO CUSTOMER (FIRST_NAME, LAST_NAME, PHONE) VALUES(:fname, :lname, :phone_no)
Using UPDATE
There are no restrictions on or extensions to the ANSI-standard UPDATE statement.
Using DELETE
There are no restrictions on or extensions to the ANSI-standard DELETE statement.
179
Data definition
Local SQL supports data definition language (DDL) for creating, altering, and dropping tables, and for creating and dropping indexes. All other ANSI-standard SQL DDL statements are not supported. In particular, views are not supported. Local SQL does not permit the substitution of variables for values in DDL statements.
The same statement for a dBASE table should omit the PRIMARY KEY definition:
CREATE TABLE "employee.db" ( LAST_NAME CHAR(20), FIRST_NAME CHAR(15), SALARY NUMERIC(10,2) DEPT_NO SMALLINT )
The following table lists SQL syntax for data types used with CREATE TABLE, and describes how those types are mapped to Paradox and dBASE types by the BDE:
Table C.1 Data type mappings
BDE Logical
fldINT16 fldINT32 fldBCD fldFLOAT fldFLOAT fldZSTRING
SQL Syntax
SMALLINT INTEGER DECIMAL(x,y) NUMERIC(x,y) FLOAT(x,y) CHARACTER(n)
Paradox
fldPDXSHORT fldPDXLONG fldPDXBCD fldPDXNUM fldPDXNUM fldPDXALPHA
dBASE
fldDBNUM fldDBNUM N/A fldDBNUM(x,y) fldDBFLOAT(x,y) fldDBCHAR
x = precision (default: specific to driver); y = scale (default: 0); n = length in bytes (default: 0); s = BLOB subtype (default: 1)
180
Table C.1
SQL Syntax
VARCHAR(n) DATE BOOLEAN BLOB(n,s) TIME TIMESTAMP MONEY AUTOINC BYTES(n)
Paradox
fldPDXALPHA fldPDXDATE fldPDXBOOL See Subtypes below fldPDXTIME fldPDXTIMESTAMP fldPDXMONEY fldPDXAUTOINC fldPDXBYTES
dBASE
fldDBCHAR fldDBDATE fldDBBOOL See subtypes below N/A N/A fldDBFLOAT(20,4) N/A fldDBBYTES (in-memory tables only)
x = precision (default: specific to driver); y = scale (default: 0); n = length in bytes (default: 0); s = BLOB subtype (default: 1)
The following table specifies how BLOB subtypes translate from SQL to Paradox and dBASE through the BDE:
Table C.2
1 2 3 4 5
SQL Subtype
Paradox
fldPDXMEMO fldPDXBINARY fldPDXFMTMEMO fldPDXOLEBLOB fldPDXGRAPHIC
dBASE
fldDBMEMO fldDBBINARY N/A fldDBOLEBLOB N/A
You can delete existing columns from a table using the following ALTER TABLE syntax:
ALTER TABLE table DROP column_name [, DROP column_name . . .]
For example, the next statement drops two columns from a Paradox table:
ALTER TABLE "employee.db" DROP LAST_NAME, DROP FIRST_NAME
ADD and DROP operations can be combined in a single statement. For example, the following statement drops two columns and adds one:
181
ALTER TABLE "employee.dbf" DROP LAST_NAME, DROP FIRST_NAME, ADD FULL_NAME CHAR[30]
Using CREATE INDEX is the only way to create indexes for dBASE tables. For example, the following statement creates an index on a dBASE table:
CREATE INDEX NAMEX ON "employee.dbf" (LAST_NAME)
Paradox users can only create secondary indexes with CREATE INDEX. Primary Paradox indexes can only be created by specifying a PRIMARY KEY constraint when creating a new table with CREATE TABLE.
The PRIMARY keyword is used to delete a primary Paradox index. For example, the following statement drops the primary index on EMPLOYEE.DB:
DROP INDEX "employee.db".PRIMARY
To drop any dBASE index, or to drop secondary Paradox indexes, provide the index name. For example, the next statement drops a secondary index on a Paradox table:
DROP INDEX "employee.db".NAMEX
182
Appendix
D
Appendix D
This appendix describes the MAST sample database provided with Delphi and used for the MASTAPP sample application. The basic MAST database is in Paradox format. A SQL version that uses the Local InterBase Server is also provided. See README.TXT for a complete list of sample databases and applications. MAST is the fictional Marine Adventures and Sunken Treasures company. MASTs customers are dive shops around the world. They sell products and supplies to these shops; the shops place orders for equipment. The following tables are used to track MASTs sales:
Table D.1 MAST tables
Information in table
Customer dive shop data, including customer number, name, etc. MAST employee information Specific items that makes up customer orders Table that maintains the next unique order number Orders placed by customer dive shops Inventory information about items on hand at MAST MAST suppliers that sell goods to MAST
Table name
CUSTOMER.DB EMPLOYEE.DB ITEMS.DB NEXTORD.DB ORDERS.DB PARTS.DB VENDOR.DB
Each table contains a primary key. To link tables, some fields and data must be duplicated among tables. A table must have a primary key or secondary index assigned to the duplicate field before it can be linked to another table. Fields that are duplicated between tables use referential integrity to make sure their values match in all tables. The following tables describe each of the MAST database tables by showing the fields contained in the table, the type of each field, the size of the alphanumeric fields, and the fields that are key fields.
183
Type
Numeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Numeric Alphanumeric Timestamp
Size
30 30 30 15 20 10 20 15 15 20
Key
*
In CUSTOMER, the CustNo field is a primary key because orders in the ORDERS table must be linked to customers. The secondary index on Company is named "ByCompany". ORDERS itself contains only information about each order placed by a customer. The structure of the EMPLOYEE table is as follows:
Field
EmpNo LastName FirstName PhoneExt HireDate Salary
Type
Long integer Alphanumeric Alphanumeric Alphanumeric Timestamp Numeric
Size
20 15 4
Key
*
Type
Numeric Numeric Numeric Long integer Numeric
Size
Key
*
OrderNo is a secondary index and is used in the master-detail link in the Orders form. The NEXTORD tables is a single-column table used to generate unique, sequential order numbers. In a multi-user environment using Paradox tables, the only way to guarantee
184
that an order number is unique is to store the last-used number in a table, and increment it each time a new number is fetched. The table is structured as follows:
Field
NewKey
Type
Numeric
Size
Key
Type
Numeric Numeric Timestamp Timestamp Long integer Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Money Numeric Money Money
Size
Key
*
20 30 30 15 20 10 20 15 7 15 6 7
In ORDERS, the link to CUSTOMER is through the CustNo field. A secondary index is defined on CustNo to ensure that ORDERS and CUSTOMERS can be sorted and linked in the same order. To be sure that values entered as CustNo in ORDERS match exactly one record in CUSTOMER, referential integrity is used to constrain values entered in the CustNo field to valid customer numbers already in the CUSTOMER table. The primary key in ITEMS is a composite of the OrderNo and ItemNo fields; these fields also have secondary indexes. This enables ITEMS to link to ORDERS (using OrderNo) in the MASTAPP Orders form. Referential integrity is used to validate the information in PARTS.
185
The PARTS table tracks the inventory of products. PARTS is structured as follows so that it can be linked to VENDORS:
Field
PartNo VendorNo Description OnHand OnOrder Cost ListPrice
Type
Numeric Numeric Alphanumeric Numeric Numeric Money Money
Size
Key
*
30 20
PartNo is the primary key for this table. Because PartNo is a secondary index, the two tables can be linked. VendorNo is the primary key of VENDORS, so it is a secondary index in PARTS and is defined to use referential integrity to make sure values entered in VendorNo match a single VendorNo entry in the VENDORS table. The VENDORS table has the following structure:
Field
VendorNo VendorName Address1 Address2 City State Zip Country Phone FAX Preferred
Type
Numeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Alphanumeric Logical
Size
30 30 30 20 20 10 15 15 15
Key
*
Using these tables, a customers information is entered only once, and then referred to in other tables. Likewise, order, item, inventory, and vendor information is entered only once, reducing storage requirements, and the chance for data entry error.
186
Index
Symbols
" (quotation mark), naming conventions 175, 176 * operator 177 + (plus) sign in property lists 103 + operator 177 / operator 177 : (colon) in SQL statements 117, 176 < operator 177 <> operator 177 = operator 177 > operator 177 ? (question mark) in SQL statements 176 || operator 177 (minus) sign in property lists 104 operator 177 (apostrophe), naming conventions 175, 176 AfterEdit event 68 AfterInsert event 68 AfterOpen event 68 AfterPost event 68 aggregate functions 141, 176177, 179 Alias Manager 172 Alias Manager dialog box (Database Desktop) 149 aliases 5, 149, 171174 changing 173 defined 149 deleting 174 local SQL and 175 predefined 20 queries 168 heterogenous 124 retrieving defaults 135 retrieving information 57 saving 172, 173 specifying 134, 172 Aliases command (Files) 149 Aliases page (BDE Configuration Utility) 172 AliasName property 135 alignment, text 108 Alignment property 33, 83, 108 ALTER TABLE keyword 181 altering See changing ancestor objects 55 AND operator 177 ANSI/OEM conversion 93 ANSI-standard SQL naming conventions 175176 Answer tables 170 apostrophe (), naming conventions 175, 176 Append method 64 AppendRecord method 65 applications 79, 93 building 19 client/server 14, 118 deploying 1618 remote servers 142145 developing 1216 client/server 127129 fundamentals 13 displaying multiple views 9597 multiuser 5, 135, 147 updating data 65 optimizing 128 sample LINKQRY 123 MASTAPP 20, 183 TWOFORMS 95 starting 173 upsizing 140142 ApplyRange method 51, 73 arithmetic operators 177 arrays 65, 72, 73 indexes 74 queries 122 stored procedures 139 AsBoolean property 35 ASCII files 6, 70 AsDateTime property 35 AsFloat property 35 AsInteger property 35 assigning values 37, 154 at run time 87, 88 calculated fields 6869, 8283 default 109, 154 names as 122 required 154 run-time 35 to buttons 114 to combo boxes 109 assignment statements 86 AsString property 35 asynchronous communication module 144 attaching to servers 5, 8, 56 remote databases 130133 Connected property and 134 connection parameters 131132 login parameters 133 attributes See display attributes; properties AUTO ODBC setting 132 AutoCalcFields property OnCalcFields event and 68 AutoDisplay property 108, 109 AutoEdit property 22, 77, 101 automatically translating data 12 AutoSize property 102 AutoUnload property 88 averages 176 AVG function 176
A
abandoning changes 64, 101, 107 Abort procedure 68 AbortOnKeyViol property 92 AbortOnProblem property 92 accessing data 79, 89, 100, 115, 116 at run time 8788 field values 30, 32 optimizing access 119 remote servers 127, 141 data sources 5, 99 networks and 5 property values 40, 86 Active property datasets 59, 101 queries 50, 119 Add command (Database Desktop) 165 Add Fields window 81 Add method 118 Add New Alias dialog box 172 ADD operations 181 adding See creating AfterCancel event 68 AfterClose event 68 AfterDelete event 68
Index
187
B
batAppend constant 89 batAppendUpdate constant 89 batch move operations 8, 75, 8992 error handling 92 BatchMove method 75 batCopy constant 89 batDelete constant 89 batUpdate constant 89 BDE (Borland Database Engine) 2, 1618, 92 retrieving information 57 BDE Configuration Utility 5, 171174 starting 171 BDE Configuration Utility Window 171 BeforeCancel event 68 BeforeClose event 63, 68 BeforeDelete event 68 BeforeEdit event 68 BeforeInsert event 68 BeforeOpen event 68 BeforePost event 68 binary collation sequence 142 binary large objects See BLOBs bitmaps 99, 108, 110 BLOB data 107 type compatibility 181 BLOBs 99, 108 BLROM800.LD 142 BOF property 61 bookmarks 6667 Boolean properties 84 Boolean types 86 Borland Database Engine See DBE Borland SQL Links 142, 170 borrowing table structures 155 Browse mode (datasets) 58 BRPARTS.DFM 22 Btrieve databases 132 buffers 60 clearing 107 flushing 67 building applications 19 building databases 1216, 147 building forms 1930 multi-table 2430 single-table 2124 buttons 78 See also specific type adding 99, 100 assigning values to 114
188
C
CalcFields mode (datasets) 58, 69 calculated fields 9, 3739, 58 assigning values 6869, 8283 defining 81, 82, 83 ordering 179 updating 38 Calculated property 33, 83 Cancel method 64 Cancel navigator button 107 canceling current operation 64, 101, 107 canceling method calls 68 CancelRange method 51, 73 CanModify property 63, 75, 120 Caption property check boxes 113 case conversions 177 sensitivity 75 centering data 83 ChangedTableName property 92 changing See also editing aliases 173 component names 23 data 6366, 100, 101 abandoning changes 64, 101, 107 committing changes 135, 136, 137 edit boxes and 36 rolling back changes 136 single-table queries 48 datasets 78 events 82, 83, 85 property values 82, 8384 table structures 159161 tables 181 values See updating values character sets 89 character strings See string lists; strings check boxes 100, 113 checking for null values 73 child tables 157 Clear method 118 clearing data buffers 107
client platforms 16 client/server applications 14, 118, 127145 deploying 142145 developing 127129 handling security 132133 transaction control 135138 client-based SQL 175 Clipboard 108 Close method datasets 60 queries 118, 122 code 23, 87 changing data 36 optimizing 61 collation sequence 142 colon (:) in SQL statements 117, 176 column headings See field names columns See also field names; fields combo boxes and multiple 111 outlining 104 combo boxes 99, 109112 assigning values 109 multiple columns 111 sorting items 110 user input and 4446 Commit method 136 COMMIT statements 135 commiting changes 135, 136, 137 communication protocols 128, 131 comparison operators 177 Component palette 6 components 2 data-aware 10, 87, 100 disabling/enabling 67 database 6, 8, 11, 5556, 133 dataset 100 field 3032 referencing 34 renaming 23 composite keys 153 concatenation operator 177 configuration files 171 configuration options 173 configuring drivers 131 confirming deletions 68, 104 Connect method 89 CONNECT.EXE 143 CONNECT.HLP 143 Connected property 134
connections (server) 5, 56 inactive 56 remote databases 8, 130133 Connected property and 134 connection parameters 131132 login parameters 133 controls See also components data 99114 read-only 101, 108 graphics 109 conversions batch move operations and 91 case 177 numbers to strings 35 strings to date/time 173 strings to numbers 36, 173 Copy command (Database Desktop) 166 Copy dialog box (Database Desktop) 166 copying data 75, 166 table structures 8, 75 text 108 CopyToClipboard method 108 COREWIN.DLL 142 COUNT function 177 counting function 177 CREATE INDEX keyword 182 Create Table dialog box (Database Desktop) 151152 SQL tables 155 CREATE TABLE keyword 180 creating forms 1930 multi-table 2430, 9395 single-table 2124 indexes 182 new tables 89, 151, 155 Paradox tables 151, 158 SQL tables 155 csDropDown constant 110 csDropDownList constant 110 csOwnerDrawFixed constant 110 csOwnerDrawVariable constant 110 csSimple constant 110 Currency property 83 current date and time 46 current field 4, 165 current operation, canceling 101, 107
current record 4, 60, 104, 165 indicator 104 setting 106 current values 34, 102 cursors 60 moving 6062, 72, 78 flickering screens and 67 CUSTOMER.DB 24, 183 customizing tables 162164 CUSTORD.DFM 24, 31 cutting graphics 108 cutting text 108 CutToClipboard method 108
D
data accessing 79, 89, 100, 115, 116 at run time 8788 field values 30, 32 optimizing access 119 remote servers 127, 141 adding 100101, 154 automatically 158 predefined values 109 to grids 103 automatically translating 12 changing 6366, 100, 101 abandoning changes 64, 101, 107 committing changes 135, 136, 137 edit boxes and 36 rolling back changes 136 single-table queries 48 confirming deletions 68, 104 copying 75, 166 defined 5 deleting See deleting displaying 9, 83, 161164 at run time 87 current values 34, 102 in grids 83, 103, 105 multiple views 9597 display-only 82, 84, 102, 107 truncated 102 editing 6364, 83, 99, 102 canceling current operation 64, 101, 107 Database Desktop and 164165 in grids 104 restrictions 164 filtering 5051 formatting 3942, 83, 85 at run time 4042 invalid, restricting 43 porting 127129
retrieving 8, 7274 from multiple tables 178, 179 specific values 179 specifying conditions 178 searching for 4243, 7072 in unkeyed fields 47 nearest match 71, 72 sorting 74, 152, 166, 173 typing to replace 164 updating 63, 6566, 101, 107 batch move operations 89 calculated fields 38 handing events 78 multiuser applications 65 read-only results 120 Refresh method and 67 validating 4347 Data Access page (Component palette) 710 data buffers 60 clearing 107 flushing 67 data controls 99114 inactive 51, 77 linking to datasets 67, 100, 101 Data Controls page (Component palette) 1011, 99100 data definition 13 Data Definition Language 180182 data entry forms 102, 158, 183 data grids 99, 103106 adding 103 displaying data 83 editing data 104 inserting records 104 linking to datasets 103 options 103104 Data Manipulation Language (DML) 176179 data masks 84 data sources 2, 7778 accessing 5, 99 networks and 5 adding 100 changing datasets 78 handling events 78 lists 111 supported 6 data templates 83, 84, 154 data types See types data-aware components 10, 87, 100 disabling/enabling 67
Index
189
database components 6, 8, 11, 5556, 133 Database Desktop 147170 adding tables 149161 copying data 166 defining fields 152 deleting records 165 editing data 164165 executing SQL statements 167169 inserting records 165 managing files 148149 opening tables 161 overview 12 password protection 159 saving SQL statements 169 sorting data 152, 166 specifying field types 152 starting 147 viewing data 161164 Database Desktop window 148 database engines 2, 16, 115, 129 Database Form Expert 21 building multi-table forms 24 Fields Editor vs. 32 opening tables at run time 23 renaming components 23 running forms 21 starting 21 Database Form Expert command (Help) 21 Database Management System (DBMS) 1 database navigator 99, 106107 buttons 106107 enabling/disabling 107 Database Properties Editor 134 database servers 5, 6, 127 aliases and 149 connecting to See connections developing applications See client/server applications database tools 1 DatabaseLogin event 133 DatabaseName property 29, 69, 116, 135 heterogenous queries 124 stored procedures 138 databases 46, 89 accessing data 100 architecture 612 building 1216, 147 defined 4 overview 24 printing reports 8, 5253 relational 150
retrieving information 57 sample 183186 Databases property 56 DataField property 45, 100 check boxes 113 combo boxes 110 dataset components 100 DataSet property 23, 77 datasets 5769, 113 changing 78 closing 59 current state 59 data sources and 77 defining 32 handling events 6869 linking to data controls 67, 100, 101 linking to data grids 103 modes 5859 moving through 6062 opening 59 rights and privileges 75 DataSource property 100, 123 date functions 177 Date Manager page (BDE Configuration Utility) 173 dates 40, 85, 173 conversion functions 86 getting current 46 returning 177 DAY constant 177 .DB files 6, 70 DB2 databases 132 dBASE tables 5, 6, 70, 175 batch move operations and 90 deleting 182 indexes 74, 153, 182 memo fields 108 naming 175 retrieving data 73 searching for data 70, 72 setting ranges 50 specifying directories 69, 149 type compatibility 180181 DBD.EXE 147 DBDEMOS alias 20 .DBF files 6, 70 DBHandle function 93 DBIPROCS.PAS 93 DBITYPES.PAS 93 DBLocale function 93 DBMS 1 DBNMP3.DLL 143 DDL See Data Definition Language default settings 85, 173
default values 109, 154 DefaultDrawing property 105 Define Field dialog box 38 Define Index dialog box (Database Desktop) 155, 156 Define Parameters dialog box 49 Delete buttons 23 Delete command (Database Desktop) 167 Delete dialog box (Database Desktop) 167 DELETE keyword 179 Delete method 64 Delete navigator button 107 DeleteTable method 75 deleting aliases 174 characters from strings 177 fields 81, 181 graphics 108 indexes 182 queries 166 records 64, 75, 104, 165 batch move operations 89 tables 75, 166, 182 text 108 DEPLOY.TXT 142 deploying applications 1618 remote servers 142145 designing forms 100 desktop databases 12 upsizing 130, 140142 destination tables 8992 detail tables 24, 7677, 9395 developing applications 1216 client/server 127129 fundamentals 13 dgAlwaysShowEditor constant 104 dgAlwaysShowSelection constant 104 dgColLines constant 104 dgColumnResize constant 104 dgConfirmDelete constant 104 dgEditing constant 104 dgIndicator constant 104 dgRowLines constant 104 dgRowSelect constant 104 dgTabs constant 104 dgTitles constant 104 .DIB files 108 directories private (:PRIV:) 149 specifying paths 57, 69 aliases and 149 working (:WORK:) 149
190
DisableControls method 50, 51, 61, 67 disabling data-aware components 67 disabling navigator buttons 107 display attributes 30, 8384 DisplayFormat property 33, 39, 41, 83, 103 displaying data 9, 83, 161164 at run time 87 current values 34, 102 in grids 83, 103, 105 multiple views 9597 displaying large images 109 displaying property values 32, 103 DisplayLabel property 33, 83 display-only data 82, 84, 102, 107 truncated 102 DisplayText property 40 DisplayWidth property 33, 83 distributing applications 1618 distribution rights 16 dmAutomatic constant 105 DML statements See Data Manipulation Language dmManual constant 105 domains 138 double quote ("), naming conventions 175, 176 DragMode property 105 drawing routines 105 Driver Manager page (BDE Configuration Utility) 173 DriverName property 135 drivers configuring 131 language 142, 143 ODBC 132, 138 retrieving information 57 DROP INDEX keyword 182 DROP operations 181 DROP TABLE keyword 182 DropConnections method 57 drop-down lists See combo boxes; lists boxes DropDownCount constant 110 dropping See deleting dsBrowse constant 59 dsCalcFields constant 59 dsEdit constant 59 dsInactive constant 59 dsInsert constant 59 dsSetKey constant 59 DSQL 121124 defined 117
E
edit boxes 99, 102 See also combo boxes changing data 36 Edit Data command (Database Desktop) 164 Edit method 63 Edit mode 107 Database Desktop 164, 165 datasets 58, 63, 77 CanModify property and 63 Edit navigator button 107 EditFormat property 83, 103 editing See also changing data 6364, 83, 99, 102 canceling current operation 64, 101, 107 Database Desktop and 164165 in grids 104 restrictions 164 graphics 108 text 108 editing methods 108 EditMask property 33, 41, 83, 84 editors Database Properties 134 Fields See Fields Editor Input Mask 84 Parameters 121, 122, 138 SQL 167169 String List 109, 117 EditRangeEnd method 73 EditRangeStart method 73 EDORDERS.DFM 38 EMPLOYEE.DB 183 Empty command (Database Desktop) 165 EmptyTable method 75 EnableControls method 50, 51, 61, 67 Enabled property 77, 101 entering SQL statements 117119, 120 at run time 118, 122 EOF property 61 errors 92 Esc key 101
events 83, 101 changing 82, 83, 85 data grids 105106 data sources 78 datasets 6869 Events tab (Object Inspector window) 85 example applications See sample applications exceptions 51, 101 exclusive locks 75 Exclusive property 75 ExecProc method 139 ExecSQL method 119 Execute method 92 executing SQL statements 116, 117, 119, 169 at run time 118 experts See Database Form Expert expressions aggregate functions and 177 EXTRACT function 177
F
fetching data See retrieving data field components 3032 Field Link Designer 7677 Field Link Designer dialog box 76 field names 83 ANSI-standards 176 assigning as values 122 disabling 104 resizing columns 163 field properties 3234 changing 83 field types See types field values See values field view 165 FieldByName method 8788 FieldName property 33, 83 fields 4, 3043 adding 31, 79, 181 Fields Editor 81 calculated 9, 3739, 58 assigning values 6869, 8283 defining 81, 82, 83 ordering 179 updating 38 current 4, 165 default settings 85 defining 152 deleting 81, 181 display-only 82, 84
Index
191
entering data 154 automatically 158 handling events 85 key 83, 152 partial keys and 73 specifying 50 moving 163 at run time 105 numeric 83, 154, 176 displaying values 83 in edit boxes 35, 36 placing scroll locks 162 reordering 31, 103, 163 at run time 105 Fields Editor 80 resizing 104, 163 selecting 104, 165 Tab key and 101, 104 setting display attributes 8384 updating See updating data Fields Editor 3032, 8083, 100 activating 9 adding fields 31, 81 changing property values 82 closing 31 Database Form Expert vs. 32 defining calculated fields 37 deleting fields 81 editing events 82 overview 10 reordering fields 80 setting property values 32 starting 80 Fields Editor window 80 Fields property 87 file servers 5, 127 aliases and 149 connecting to See connections developing applications See client/server applications files See also applications; databases configuration 171 distributing 16, 17 opening 148 script 118 temporary 57, 92, 149, 170 text 6, 70 filters 5051 finding field values 42, 7072 nearest match 71, 72 FindKey method 72 FindNearest method 72 First method 60 First navigator button 106
flickering screens 67 floating-point numbers 86 flushing data buffers 67 focus, setting 85 FocusControl method 85 Form Expert See Database Form Expert FormatDateTime routine 85 FormatFloat routine 85 FormatInteger routine 85 formatting data 3942, 83, 85 at run time 4042 formatting text 40 forms 1930 data entry 102, 158, 183 designing 100 multi-table 2430, 76 creating 9395 order entry 93, 112 printing 53 running 21 single-table 2124 FreeBookmark method 67 freeing memory 67 functions See also methods; routines aggregate 141, 176177, 179 date 177 mathematical 141 search 70 string manipulation 177
headings See field names Help Hints 107 heterogeneous joins 179 heterogenous queries 124 hierarchy 7, 55 Hints property 107 horizontal dividing lines, enabling/disabling 104 HOUR constant 177
I
icons Data Access page 7 Data Controls page 10 IDAPI.CFG 171 IDAPI.CNF 17 IDAPI01.DLL 17 IDAPICFG.EXE 17, 171 IDAPICFG.HLP 17 IDASCI01.DLL 17 IDBAT01.DLL 17 IDDBAS01.DLL 17 IDODBC01.DLL 17 IDPDX01.DLL 17 IDQRY01.DLL 17 IDR10009.DLL 17 ILD01.DLL 17 image boxes 99 images 108 scrolling through 109 inactive data controls 51, 77 inactive database connections 56 Inactive mode (datasets) 58 Index property 33, 83 indexes 7475, 152154, 180 See also key fields creating 182 deleting 182 naming 156 primary 74 secondary 71, 72, 74, 154, 182 SQL tables 153154, 155157, 160 IndexFieldCount property 74 IndexFieldNames property 50, 71 IndexFields property 74 IndexName property 71, 74 Informix servers 143 Informix tables 6, 90, 91 transactions 138 inheritance 55 InitialValues property 88 inner joins 178 input focus 85
G
.GDB files 6 GDS.DLL 143 GetAliasNames method 57 GetAliasParams method 57 GetBookmark method 67 GetDatabaseNames method 57 GetDriverNames method 57 GetDriverParams method 57 GetIndexNames method 74 GetTableNames method 57 GoToBookmark method 67 GoToCurrent method 76 GoToKey method 70 GoToNearest method 70, 71, 72 graphics 108 displaying large 109 editing 108 grids See data grids
H
Handle function 93 handles 93
192
Input Mask Editor 84 Input Mask Editor window 84 INSERT keyword 179 Insert method 64 Insert mode (datasets) 58, 64, 106 CanModify property and 63 Insert navigator button 106 InsertRecord method 65 instantiating TField 103 integers 86 IntegralHeight property 110 integrity violations 92 interactive SQL 129 INTERBAS.MSG 143 InterBase Server (LIBS) 127, 129130 InterBase tables 5, 6, 130 accessing 143 batch move operations and 91 transactions 138 InterBase Workgroup Server for Windows NT 144 International settings 85 invalid data, restricting 43 invoices 44, 113 IS NULL operator 177 ISAM.IEM 143 isolation levels (transactions) 137138 ISQL 129 ItemHeight property combo boxes 110 list boxes 111 Items property 45 combo boxes 109 list boxes 110, 113 radio buttons 114 ITEMS.DB 183 iteration 61, 62, 87
keyboard events 101, 106 KeyExclusive property 72 ranges and 74 KeyFieldCount method 71 KeyViolTableName property 92 keywords See also SQL keywords naming conventions and 175, 176
LookupField property 45, 111 LookupSource property 45, 111 loops 61, 62 loRowLines constant 111 loTitles constant 111 LOWER function 177 lowercase conversions 177
M
M3OPEN.DLL 144 M3OPEN.EXE 144 maintaining database connections 134 Mappings property 91 masks 84 MAST sample database 183186 MASTAPP sample application 20, 183 master tables 24, 7677, 9395 MasterFields property 76 MasterSource property 76, 94 mathematical functions 141 MAX function 177 maximum values 51, 83, 154, 177 MaxLength property 108 MaxValue property 83 MBW.EXE 144 memo boxes 99 memo fields 108 memory, freeing 67 memos 107108 scrolling through 108 menu items 78 messages 71 metadata 138, 141 methods See also functions; procedures bookmarks 67 canceling calls 68 editing 108 MFTP.EXE 144 MHPARPA.DLL 144 Microsoft Access databases 132 Microsoft Named Pipes protocol 144 Microsoft SQL servers 6, 142 transactions 138 MIN function 176 minimum values 51, 83, 154, 176 minus () sign in property lists 104 MINUTE constant 177 MinValue property 84 MNETONE.EXE 144 MNOVLWP.DLL 144
Index
L
labels 101102 language drivers 142, 143 large images 109 Last method 60 Last navigator button 106 LDLLSQLW.DLL 143 left justifying data 83 LIBS See InterBase Server linking data controls to datasets 67, 100, 101 linking data grids to datasets 103 linking queries 123 linking tables 94, 150 one-many-many links 27 one-to-many links 24, 76 LINKQRY sample application 123 list boxes 99, 100, 109, 110 See also combo boxes lists 111 scrolling through 110, 112 sorting items 110 string See string lists user input and 4445 live results 48, 120 See also SQL queries LoadFromFile method 118 local buffers 60 clearing 107 flushing 67 Local Interbase Server (LIBS) See InterBase Server Locale function 93 locating field values 42, 7072 nearest match 71, 72 locking tables 75 loColLines constant 111 logical operators 177 Login dialog box 132 login parameters 133 LoginPrompt property 133 lookup lists 111 lookup tables 4546, 158 LookupDisplay property 45, 111
J
joins 178 heterogeneous 179
K
KeepConnections property 56, 134 key fields 83, 152 See also indexes partial keys and 73 specifying 50 key violations 92
193
Mode property 89 modifying See changing monetary values 83, 85 MONTH constant 177 mouse events 101, 105 MoveBy method 62 MoveCount property 92 moving cursors 6062, 72, 78 fields 163 at run time 105 text 108 moving among fields 104, 165 Tab key and 101, 104 moving through images 109 moving through lists 110, 112 moving through memos 108 moving through tables 6062, 104 Database Desktop and 162, 165 MPATHWAY.DLL 144 MPCNFS.EXE 144 MPCNFS2.EXE 144 MPCNFS4.DLL 144 MSOCKLIB.DLL 144 multi-line text 107 multiple query statements 118 multi-table forms 2430, 76 creating 9395 Paradox tables 157, 158 multi-table queries 124, 178 heterogeneous joins 179 multiuser applications 5, 135, 147 See also client/server applications; networks updating data 65 MVWASYNC.EXE 144 MWINTCP.EXE 144
Next method 60 Next navigator button 106 Next Record buttons 23 NEXTORD.DB 183 nil values 65 NOT operator 177 NOT SHARED setting 137 Novell SPX/IPX interface 131, 144 Now function 46 null values 65, 121 checking for 73 stored procedures 139 Number Manager page (BDE Configuration Utility) 173 numbers conversion functions 86 converting strings to 36, 173 to strings 35 numeric fields 83, 154, 176 displaying values 83 in edit boxes 35, 36 NWCALLS.DLL 144 NWIPXSPX.DLL 144
O
object hierarchy 7, 55 Object Inspector displaying property values 32, 33, 103 ODBC data sources 6 ODBC driver 132, 138 ODBC.NEW 17 ODBCINST.NEW 17 OEM conversion 93 OnCalcFields event 38, 58, 6869, 82 OnColEnter event 105 OnColExit event 105 OnDataChange event 78 OnDblClick event 105 OnDragDrop event 105 OnDragOver event 105 OnDrawDataCell event 105, 106 one-many-many links 27 OnEndDrag event 106 OnEnter event 106 one-to-many links 24, 76 OnExit event 106 OnGetText event 85 OnKeyDown event 106 OnKeyPress event 106 OnKeyUp event 106 OnLogin event 133
N
Name property 32, 33, 84 naming directories 149 fields 176 indexes 156 tables 175 navigator See database navigator nbDelete constant 23 nbNext constant 23 NetFileDir property 57 networks 127, 144, 149 accessing 5 temporary files and 149
194
OnNewRecord event 68 OnSetText event 85 OnStateChange event 59, 78 OnUpdateData event 78 OnValidate event 43, 46 Open command (Database Desktop) 148, 161 Open method datasets 59 queries 119 Open Table dialog box (Database Desktop) 161 opening datasets 59 files 148 queries 168 tables 161 at run time 23 operators (local SQL statements) 177 optimizing applications 128 optimizing code 61 optimizing queries 121 Options property combo boxes 111 data grids 103 OR operator 177 ORA6WIN.DLL 142 ORA7WIN.DLL 142 Oracle servers 142 Oracle tables 6, 90, 91 stored procedures 140 transactions 138 ORAWE850.LD 142 order entry forms 93, 112 ORDERS.DB 24, 183 OS.IEM 143 outer joins 178 outlining records and fields 104 output 53 Overload property 140 overloading stored procedures 140
P
Paradox tables 5, 6, 70, 175 batch move operations and 90 creating 151, 158 deleting 182 indexes 74, 152, 154, 182 key fields 152 memo fields 108 multi-table forms 157 lookup tables and 158 naming 175
password protection 159 referential integrity 157158 restructuring 159 retrieving data 73 searching for data 70, 72 setting ranges 50 specifying directories 69, 149 type compatibility 180181 validity checks 154 ParamByName method 122 ParamByName property 138 parameterized statements 117 parameters connection 131132 login 133 retrieving information 57 SQL statements 117, 121, 176 arrays and 122 assigning names 122 null values 121 setting at run time 121 stored procedures 138139 Parameters Editor 121, 122, 138 Params property 50, 122, 131 parent tables 157 parsing query statements 121 partial keys 73 PARTS.DB 183 passthrough SQL 120, 136, 167 transactions 136, 137 isolation levels 137 passwords 159 PasteFromClipboard method 108 pasting graphics 108 pasting text 108 picture strings 83, 84, 154 placing bookmarks 6667 placing locks 75 platforms 128 plus (+) sign in property lists 103 pointers 60 porting data 127129 Post method 63, 64 Edit method and 64 OnCalcFields event and 69 Post navigator button 107 posting records 63, 64, 102 automatically 107 data grids 105 predefined aliases 20 predefined values 109 Prepare method 116, 121122, 139 Preview property 52
primary indexes 74, 152, 182 Print method 53 printing forms 53 printing reports 8, 5253 Prior method 60 Prior navigator button 106 private directories (:PRIV:) 149 Private Directory command (Database Desktop) 149 PrivateDir property 57 privileges 75 ProblemTableName property 92 procedures See also methods; routines stored 8, 57, 138140 executing 139 overloading 140 project files 16 projects See applications properties 6, 83 accessing 40, 86 Boolean 84 changing 82, 8384 field 3234, 83 values, displaying 32, 103 Properties menu (Database Desktop) 163 Properties tab (Object Inspector window) 83 protocol (communications) 128, 131
R
radio buttons 100, 114 ranges 5051, 73 canceling 51 maximum values 51 minimum values 51 RDS.IEM 143 read-only controls 101, 108 graphics 109 read-only privileges 75 ReadOnly property 33, 75, 84 CanModify property and 63 read-only results 48, 120 See also SQL queries ReCalcReport method 89 records adding 64, 65, 106, 165 batch move operations 89 data grids and 104 current 4, 60, 104, 165 indicator, setting 104 setting 106 data grids and 103, 105 deleting 64, 75, 104, 165 batch move operations 89 moving through 6062 ordering 152, 179 outlining 104 posting 63, 64, 102, 105 automatically 107 resizing 163 selecting 104, 106, 165 specific sets 47, 50 updating See updating data Redistributable BDE 16 redrawing screens 105, 108, 109 referencing components 34 referential integrity 157158 Referential Integrity dialog box (Database Desktop) 158 Refresh method 67 Refresh navigator button 107 relational databases 150 See also databases releasing memory 67 remote servers 5, 127 aliases and 149 connecting to 8, 130133, 134 deploying applications 142145 developing applications 12, 15 REMOTE.DLL 143 removing See deleting Rename command (Database Desktop) 166
Index
Q
QBE (defined) 169 queries 9, 4750, 169170 See also SQL queries deleting 166 dynamic 48 multi-table 124, 178 heterogeneous joins 179 opening 168 renaming 166 single-table 48 specifying table names 9 static 47 query by example (defined) 169 Query component 115, 117 question mark (?) in SQL statements 176 quotation mark ("), naming conventions 175, 176
195
Rename dialog box (Database Desktop) 166 renaming components 23 queries 166 tables 166 reordering fields 31, 103, 163 at run time 105 Fields Editor 80 repeat. . . until loops 62 ReportDir property 52, 88 ReportName property 52, 88 reports 8, 8889 printing 5253 ReportSmith 8, 52, 88 deploying applications 145 printing reports 5253 ReportSmith Runtime 145 RequestLive property 48, 120 Required property 43 required values 154 reserved words See also SQL keywords naming conventions and 175, 176 resizing fields 104, 163 resizing records 163 restoring previous values 64, 101, 107 Restructure command (Database Desktop) 159 Restructure Table dialog box (Database Desktop) 159, 160 restructuring tables 159161 retrieving data 8, 7274 from multiple tables 178, 179 specific values 179 specifying conditions 178 right justifying data 83 Rollback method 136 ROLLBACK statements 135 rolling back changes 136 rounding 86 routines See also functions; methods; procedures drawing 105 rows See records RS_RUN directory 52 Run method 52, 88 Run SQL command (Database Desktop) 169 Run Visual Query Builder command 118 RunMacro method 88
running SQL statements 116, 117, 119, 169 at run time 118
S
sample applications LINKQRY 123 MASTAPP 20, 183 TWOFORMS 95 sample database 183186 saving aliases 172, 173 SQL statements 118, 169 screens flickering 67 redrawing 105, 108, 109 script files 118 scroll bars 108 scroll locks 162 ScrollBars property 108 scrolling through images 109 scrolling through lists 110, 112 scrolling through text 108 search conditions (SQL queries) 178 search functions 70 search mode 70 searching for data 4243, 7072 in unkeyed fields 47 nearest match 71, 72 SECOND constant 177 secondary indexes 154 deleting 182 searching on 71, 72, 74 security 132133 SECURITY.IEM 143 Select Alias command (Database Desktop) 168 Select Alias dialog box (Database Desktop) 168 SELECT keyword 178 SELECT statements 118, 120, 178179 selecting See also searching for data fields 104, 165 Tab key and 101, 104 records 104, 106, 165 specific sets 47, 50 selection bars (grids) 104 servers 5, 6, 127 aliases and 149 connecting to See connections developing applications See client/server applications
Session component 56 set functions 176177, 179 SetFields method 65 SetKey method 70, 71 SetKey mode (datasets) 58, 70 SetRange method 73 SetRangeEnd method 51, 73 SetRangeStart method 51, 73 setting locks 75 setting property values 32 SetVariable method 89 SHARED AUTOCOMMIT setting 137 SHARED NOAUTOCOMMIT setting 137 Show SQL command (Database Desktop) 168 ShowHint property 107 ShowMessage function 71 single quote (), naming conventions 175, 176 single-table forms 2124 single-table queries 48 Size property 84 Sort command (Database Desktop) 166 sort order 74 Sort Table dialog box (Database Desktop) 166 Sorted constant 110 sorting data 74, 152, 166 configuration options 173 sorting items in lists 110 source tables 8992 specifying aliases 134, 172 spreadsheets 99 SQL database servers 6 SQL Editor (Database Desktop) 167169 saving statements 169 starting 168 SQL Editor window (Database Desktop) 167 SQL keywords ALTER TABLE 181 COMMIT 135 CREATE INDEX 182 CREATE TABLE 180 DELETE 179 DROP INDEX 182 DROP TABLE 182 INSERT 179 naming conventions 175, 176 ROLLBACK 135 SELECT 178 UPDATE 179
196
SQL Links 142 SQL property 116, 117, 118 SQL queries 9, 115125 adding new fields 181 creating indexes 182 deleting fields 181 entering statements 117119, 120 at run time 118, 122 heterogenous 124 linking 123 live vs. read-only results 120 local (client-based) 175182 data definition 180182 data manipulation 176179 naming conventions 175176 operators 177 multi-table 124, 178 heterogeneous joins 179 optimizing 121 preparing 121122 retrieving specific values 179 running statements 116, 117, 119, 167169 at run time 118 saving statements 118, 169 specifying search conditions 178 specifying table names 9 tutorial 4750 type compatibility 180181 updating 50 SQL script files 118 SQL Statement command (Database Desktop) 168 SQL tables creating 155 indexes 74, 153154, 155157, 160 naming 156 naming 175 restructuring 160 retrieving data 73 searching for data 70, 72 setting ranges 50 sorting data 166 specifying directories 69 updating data 65 validity checks 154 SQL.IEM 143 SQL_IB.CNF 143 SQL_INF.CNF 143 SQL_ORA.CNF 142 SQL_SS.CNF 142 .SQL files 169
SQL13WIN.DLL 142 SQLD_IB.DLL 143 SQLD_IB.HLP 143 SQLD_INF.DLL 143 SQLD_INF.HLP 143 SQLD_ORA.DLL 142 SQLD_ORA.HLP 142 SQLD_SS.DLL 142 SQLD_SS.HLP 142 SQLPASSTHRUMODE setting 136, 136137 SQLWIN.DLL 142 starting applications 173 BDE Configuration Utility 171 Database Form Expert 21 Fields Editor 80 Input Mask Editor 84 Parameters Editor 138 StartTrans method 136 StartTransaction method 136 State property 59 static queries 47 static SQL statement (defined) 117 stored procedures 8, 57, 138140 executing 139 overloading 140 parameters 138139 StoredProcName property 138 String List Editor 109 entering SQL statements 117 string lists 117 associating with buttons 114 sorting items 110 string manipulation functions 177 strings 73 concatenating 177 conversion functions 86 converting case 177 to date/time 173 to numbers 36, 173 picture 83, 84, 154 removing repeating characters 177 returning parts of 177 Structured Query Language See SQL Style property combo boxes 110 subqueries 178, 179 SUBSTRING function 177
substrings, returning 177 Subtract command (Database Desktop) 165 SUM function 176 sums 176 supported data sources 6 Sybase servers 121, 142 Sybase tables 6, 90, 91, 156 transactions 138 SYDC437.LD 143 SYDC850.LD 143 System Manager page (BDE Configuration Utility) 173
T
Tab key 101 tabbing through fields 101, 104 Table Type dialog box (Database Desktop) 151 Table window (Database Desktop) 161 TableName property 22, 69 tables 4, 180 adding 8 Database Desktop 149161 Answer 170 changing 181 child 157 configuration options 173 creating new 89, 151, 155 Paradox 151, 158 SQL 155 customizing views 162164 deleting 75, 166, 182 destination 8992 detail 24, 7677, 9395 linking 94, 150 one-many-many links 27 one-to-many links 24, 76 locking 75 locking columns 162 lookup 4546, 158 master 24, 7677, 9395 moving through 6062, 104 Database Desktop and 162, 165 multiple views 9597, 180 naming, ANSI standards 175 opening 161 at run time 23 parent 157 placing bookmarks 6667 renaming 166 retrieving information 57 source 8992
Index
197
specifying for queries 9 structure borrowing 155 changing 159161 copying 8, 75 types 6970 TableType property 69 taCenter constant 33 Tag property 84 taRightJustify constant 33 TBatchMove component 8, 8992 TBCDField type 86 TBlobField type 86 TBookmark type 67 TBooleanField type 86 TBytesField type 86 TCP/IP interface 16, 131, 144 TCurrencyField type 85, 86 TDatabase component 8, 133135 TDataSet class 8 TDataSource component 6, 8, 10, 7778, 100 multiple views and 95 TDateField type 85, 86 TDateTimeField type 85, 86 TDBCheckBox component 100, 113 TDBComboBox component 99, 109110 TDBEdit component 99, 102 TDBGrid component 99, 103106 adding 101, 103 TDBImage component 99, 108 TDBListBox component 99, 109, 110 TDBLookupCombo component 100, 109, 111112 TDBLookupList component 100, 109, 112 TDBMemo component 99, 107108 TDBNavigator component 99, 106107 adding 101 enabling/disabling buttons 107 TDBRadioGroup component 100, 114 TDBText component 99, 101102 telephone numbers 40, 41 templates data entry 83, 84, 154 temporary files 57, 92, 149, 170
198
.TXT files 6 text 108 See also data adding 107 aligning 108 editing 108 formatting 40 scrolling through 108 wordwrapping 108 text files 6, 70 text strings See string lists; strings TField component 30, 33, 40, 7987, 100 disabling 103 instantiating 103 overview 8 referencing 34 TFloatField type 84, 85, 86 TGraphicField type 86 tiDirtyRead constant 137 time 85, 173 conversion functions 86 returning 177 Time Manager page (BDE Configuration Utility) 173 timer events 101 timestamps 46 TIMEZONE_HOUR clause 177 TIMEZONE_MINUTE clause 177 TIntegerField type 85, 86 tiReadCommitted constant 137 tiRepeatableRead constant 137 TMemoField type 86 tool bars 22 Database Desktop windows 148, 161, 168 totaling numeric values 176 TQuery component 57, 100, 115117 overview 6, 8, 910 TDataSource and 10 TTable vs. 116, 120 transactions 100, 128, 135138 implicit vs. explicit control 136 isolation levels 137138 TransIsolation property 137 translating data 12 Transliterate property 89 TReport component 8, 52, 8889 TRIM function 177 truncated data 102 try...except blocks 119 try...finally blocks 51, 61, 67 TSession component 5657, 134
TSmallIntField type 85, 86 TStoredProc component 8, 57, 138 TStringField type 84, 86 TStrings type 117 TTable component 6, 89, 57, 6977, 100 multiple views and 96 TDataSource and 10 TQuery vs. 116, 120 TTimeField type 85, 86 TUTILITY.DLL 17 tutorial 1953 TVarBytesField type 86 TWOFORMS.DPR 95 TWordField type 85, 86 .TXT files 70 types 31 batch move operations and 9091 converting 86 editing 164 specifying 152 SQL-compatible 180181 typing to replace entries 164
U
UniDirectional property 119 unique indexes 153, 156 UnPrepare method 122 UPDATE keyword 179 UPDATE statements 120 UpdateMode property 6566 updating data 63, 6566, 101, 107 batch move operations 89 calculated fields 38 handling events 78 multiuser applications 65 read-only results 120 Refresh method and 67 updating queries 50 UPPER function 177 uppercase conversions 177 upsizing desktop databases 130, 140142 Utilities menu (Database Desktop) 165
V
validity checks 4347, 154 types 43 Value property 86 ValueChecked property 113
values accessing 30, 32 assigning 37, 154 at run time 87, 88 calculated fields 6869, 8283 default 109, 154 names as 122 required 154 run-time 35 to buttons 114 to combo boxes 109 averaging 176 changing edit boxes and 36 changing See updating data converting numbers to strings 35 string to date/time 173 string to numbers 36, 173 counting 177 currency 83, 85 display formats 85 displaying current 34, 102 finding 42, 7072 nearest match 71, 72 minimum/maximum 83, 154 aggregate functions 176177 specifying 51 nil 65 null 65, 121 checking for 73 stored procedures 139 predefined 109 property accessing 40, 86 changing 82, 8384 displaying 32, 103 setting 32 restoring previous 64, 101, 107 retrieving specific 179 rounding 86 totaling 176 typing to replace entries 164 updating See updating data Values property 114 ValueUnchecked property 113 variables local SQL statements 176, 180 VBX controls 16 VENDOR.DB 183 vertical dividing lines, enabling/ disabling 104 viewing See displaying
views 9597, 180 Visible property 33, 84, 103 VisibleButtons property 23, 107 Visual Basic controls 16 Visual Query Builder 10, 118119 Visual Query Builder window 118 VSL.INI 144
W
W3DBLIB.DLL 143 WhereAll constant 66 WhereChanged constant 66 WhereKeyOnly constant 66 Windows for Workgroups 144 Windows ISQL 129 Winsock 1.1 compliant TCP/IP products 144 WINSOCK.DLL 144 WordWrap property 108 wordwrapping text 108 working directories (:WORK:) 149 Working Directory command (Database Desktop) 149 write privileges 75
Index
199
Delphi
Borland International, Inc., 100 Borland Way P.O. Box 660001, Scotts Valley, CA 95067-0001
Borland may have patents and/or pending patent applications covering subject matter in this document. The furnishing of this document does not give you any license to these patents. COPYRIGHT 1995 Borland International. All rights reserved. All Borland products are trademarks or registered trademarks of Borland International, Inc. Other brand and product names are trademarks or registered trademarks of their respective holders.
9596979899-987654321 W1
Contents
Chapter 1
Searching for field values. . . . . . . . . . . . . 42
Introduction
What you should know first . . . . . . . . . . . . 1 Overview of Delphis database features and capabilities . . . . . . . . . . . . . . . . . . . 2 What is a database?. . . . . . . . . . . . . . . . . . 4
What is data? . . . . . . . . . . . . . . . . . . . . .5 What is data access? . . . . . . . . . . . . . . . . .5 Data sources . . . . . . . . . . . . . . . . . . . . . .6
Chapter 3
55
Using datasets . . . . . . . . . . . . . . . . . . . . 57
Dataset states . . . . . . . . . . . . . . . . . . Opening and closing datasets . . . . . . . . Navigating datasets . . . . . . . . . . . . . . The Next and Prior methods . . . . . . . . The First and Last methods . . . . . . . . . The BOF and EOF properties . . . . . . . . The MoveBy function . . . . . . . . . . . . Modifying data in datasets . . . . . . . . . . The CanModify property . . . . . . . . . . Posting data to the database . . . . . . . . Editing records . . . . . . . . . . . . . . . . Adding new records . . . . . . . . . . . . . Deleting records . . . . . . . . . . . . . . . Canceling changes . . . . . . . . . . . . . . Working with entire records . . . . . . . . Setting the update mode. . . . . . . . . . . Bookmarking data . . . . . . . . . . . . . . . Disabling, enabling, and refreshing data-aware controls . . . . . . . . . . . . . Using dataset events. . . . . . . . . . . . . . Abort a method . . . . . . . . . . . . . . . . Using OnCalcFields . . . . . . . . . . . . . Specifying the database table . . . . . . . . The TableType property . . . . . . . . . . . Searching a table . . . . . . . . . . . . . . . . Using Goto functions . . . . . . . . . . . . Using Find functions. . . . . . . . . . . . . The KeyExclusive property . . . . . . . . . Limiting records retrieved by an application . . . . . . . . . . . . . . . . . . Using partial keys . . . . . . . . . . . . . . The KeyExclusive property . . . . . . . . .
i
Developing applications for desktop and remote servers . . . . . . . . . . . . . . . . . . . 12 Database application development methodology. . . . . . . . . . . . . . . . . . . . 13
Development scenarios . . . . . . . . . . . . . . 13 Database application development cycle . . . . 13 Design phase . . . . . . . . . . . . . . . . . . . 14 Implementation phase. . . . . . . . . . . . . . 15 Deployment phase . . . . . . . . . . . . . . . . 15
Deploying an application . . . . . . . . . . . . . 16
Deploying BDE support . . . . . . . . . . . . . . 16 Language drivers. . . . . . . . . . . . . . . . . 17 ODBC Socket . . . . . . . . . . . . . . . . . . . 18
Chapter 2
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
58 59 60 60 60 61 62 63 63 63 63 64 64 64 64 65 66 67 68 68 68 69 69 70 70 72 72
19
. 20 . 21 . 24 . 27 . 30 . 32 . 34 . 35 . 37 . 39 . 40
Building forms . . . . . . . . . . . . . . . . . . . 19
Using TTable. . . . . . . . . . . . . . . . . . . . . 69
. . 72 . . 73 . . 74
Indexes . . . . . . . . . . . . . . . . . . . . . . . . 74 The Exclusive property . . . . . . . . . . . . . . 75 Other properties and methods . . . . . . . . . . 75 The ReadOnly and CanModify properties . . . . . . . . . . . . . . . . . . . . 75 The GoToCurrent method . . . . . . . . . . . 76 Creating master-detail forms . . . . . . . . . . . 76 The Field Link Designer. . . . . . . . . . . . . 76
Displaying data as labels with TDBText. . . . 101 Displaying and editing fields with TDBEdit. . . . . . . . . . . . . . . . . . . . . . 102
Editing a field. . . . . . . . . . . . . . . . . . . .102
Using TDataSource . . . . . . . . . . . . . . . . . 77
Using TDataSource properties . The DataSet property . . . . . The Enabled property . . . . . The AutoEdit property . . . . Using TDataSource events . . . The OnDataChange event . . The OnUpdateData event. . . The OnStateChange event . . . . . . . . . . . . . . . . . . 77 . . . . . . . . 77 . . . . . . . . 77 . . . . . . . . 77 . . . . . . . . 78 . . . . . . . . 78 . . . . . . . . 78 . . . . . . . . 78
Displaying and editing BLOB text with TDBMemo . . . . . . . . . . . . . . . . . . . . 107 Displaying BLOB graphics with TDBImage . . . . . . . . . . . . . . . . . . . . 108 Using list and combo boxes . . . . . . . . . . . 109
TDBComboBox. . . TDBListBox . . . . . TDBLookupCombo TDBLookupList . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .109 .110 .111 .112
Chapter 5
115
.116 .116 .117 .117 .118 .119 .119 .120 .120 .121 .121 .122 .122 .123 .124
Chapter 4
99
Chapter 6
127
ii
Relational tables . . . . . . . . . . . . . . . Planning tables . . . . . . . . . . . . . . . . Creating a new table. . . . . . . . . . . . . . Defining fields . . . . . . . . . . . . . . . . . Field names . . . . . . . . . . . . . . . . . . Adding, deleting, and rearranging fields . . . . . . . . . . . . . . . . . . . . . Specifying field type . . . . . . . . . . . . . Using indexes. . . . . . . . . . . . . . . . . . Keys in Paradox tables. . . . . . . . . . . . A dBASE tables index . . . . . . . . . . . . An SQL tables index. . . . . . . . . . . . . Defining secondary indexes . . . . . . . . . Specifying validity checks . . . . . . . . . . Borrowing a table structure . . . . . . . . . Creating an SQL table . . . . . . . . . . . . . Creating indexes on SQL tables . . . . . . Naming SQL indexes . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
.150 .150 .151 .152 .152 .152 .152 .152 .152 .153 .153 .154 .154 .155 .155 .155 .156
Upsizing . . . . . . . . . . . . . . . . . . . . . . 140
Upsizing the database . . . . . . . . . . . . . . 140 Upsizing the application. . . . . . . . . . . . . 141
Appendix A
147
iii
Appendix B
Using SELECT . . . . . . . . . . . . . . . . Using the FROM clause . . . . . . . . . . Using the WHERE clause . . . . . . . . . Using the ORDER BY clause . . . . . . . Using the GROUP BY clause . . . . . . . Heterogeneous joins . . . . . . . . . . . . Using INSERT . . . . . . . . . . . . . . . . Using UPDATE . . . . . . . . . . . . . . . Using DELETE . . . . . . . . . . . . . . . . Using CREATE TABLE . Using ALTER TABLE . . Using DROP TABLE . . Using CREATE INDEX . Using DROP INDEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
.178 .178 .178 .179 .179 .179 .179 .179 .179 .180 .181 .182 .182 .182
Appendix C
175
Naming conventions for tables . . . . . . . . . 175 Naming conventions for columns . . . . . . . 176 Data manipulation . . . . . . . . . . . . . . . . 176
Parameter substitutions in DML statements . . . . . . . . . . . . . . . Supported set (aggregate) functions . Supported string functions . . . . . . Supported date function. . . . . . . . Supported operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 176 177 177 177
Appendix D
183 187
iv
Tables
1.1 1.2 Database features summary . . . . . . . . . Additional Delphi Client/Server database features . . . . . . . . . . . . . . . . . . . . . . 1.3 Delphi data sources. . . . . . . . . . . . . . . 1.4 Data Access components . . . . . . . . . . . 1.5 Data Controls components . . . . . . . . . . 1.6 Redistributable Borland Database Engine files . . . . . . . . . . . . . . . . . . . . . . . . 2.1 Important TTable properties for a single-table form . . . . . . . . . . . . . . . . 2.2 Important TDataSource properties for a single-table form . . . . . . . . . . . . . . . 2.3 Important TDBGrid properties for a single-table form . . . . . . . . . . . . . . . . 2.4 Important TDBNavigator properties for a single-table form . . . . . . . . . . . . . . . . 2.5 Important detail table properties. . . . . . . 2.6 Important component properties for a master-detail form . . . . . . . . . . . . . . . 2.7 Important component properties for a one-many-many form . . . . . . . . . . . . . 2.8 Important TField design-time properties . . 2.9 Important TField design-time properties . . 2.10 Important TDBComboBox properties. . . . 2.11 Important TDBComboBox properties. . . . 2.12 Important TReport properties . . . . . . . . 3.1 TSession methods. . . . . . . . . . . . . . . . 3.2 Dataset states . . . . . . . . . . . . . . . . . . 3.3 Navigational methods and properties . . . 3.4 Methods to insert, update and delete data in datasets . . . . . . . . . . . . . . . . . . . . 3.5 Methods used to work with entire records. 3.6 Dataset events . . . . . . . . . . . . . . . . . . 3.7 TField properties . . . . . . . . . . . . . . . . . .2 . . . . .4 .6 .8 11 3.8 3.9 3.10 3.11 3.12 3.13 3.14 . 22 . 22 . 23 . 23 . 26 . 26 . . . . . . . . . . . . . 29 33 40 44 45 52 57 58 60 63 64 68 83 4.1 4.2 4.3 4.4 4.5 5.1 6.1 6.2 6.3 6.4 6.5 6.6 6.7 A.1 C.1 C.2 D.1 3.15 TField formatting routines . . . . . . . . . Published TField events . . . . . . . . . . TField conversion functions . . . . . . . . Important TReport methods. . . . . . . . Batch move modes . . . . . . . . . . . . . Physical data type translations from Paradox tables to tables of other driver types . . . . . . . . . . . . . . . . . . Physical data type translations from dBASE tables to tables of other driver types . . . . . . . . . . . . . . . . . . Physical data type translations from InterBase tables to tables of other driver types . . . . . . . . . . . . . . . . . . Data controls . . . . . . . . . . . . . . . . . Expanded TDBGrid Options properties . TDBGrid events . . . . . . . . . . . . . . . TDBNavigator buttons . . . . . . . . . . . Data-aware list box and combo box controls . . . . . . . . . . . . . . . . . . . . Types of query result sets . . . . . . . . . Server transaction isolation levels. . . . . Oracle SQL Link files . . . . . . . . . . . . Sybase SQL Link files . . . . . . . . . . . . Informix SQL Link files. . . . . . . . . . . InterBase SQL Link files . . . . . . . . . . Winsock 1.1 client files . . . . . . . . . . . Non-Winsock compliant TCP support files . . . . . . . . . . . . . . . . . . . . . . . Paradox validity checks. . . . . . . . . . . Data type mappings. . . . . . . . . . . . . BLOB subtype mappings. . . . . . . . . . MAST tables . . . . . . . . . . . . . . . . . . . . . . . . . . . .85 .85 .86 .88 .89
. 17
. . .90 . . .90 . . . . . . . . . . . . . . . . . . . .91 . .99 . 104 . 105 . 106 . 109 . 120 . 138 . 142 . 142 . 143 . 143 . 144 . 144 . 154 . 180 . 181 . 183
Figures
1.1 1.2 1.3 1.4 1.5 1.6 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10 2.11 2.12 2.13 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 4.10 4.11 4.12 Delphi database architecture . . . . . . . . . . . 2 Structure of a table . . . . . . . . . . . . . . . . . 4 Database components architecture . . . . . . . 7 Data Access page of the Component palette . . 7 The Data Controls page of the Component palette. . . . . . . . . . . . . . . . . . . . . . . . 10 Development cycle . . . . . . . . . . . . . . . . 14 Database forms described in the tutorial . . . 20 Building a single-table form using the Database Form Expert . . . . . . . . . . . . . . 21 A single-table form. . . . . . . . . . . . . . . . 22 Linking fields in a master-detail form . . . . . 25 A master-detail form. . . . . . . . . . . . . . . 26 One-many-many form . . . . . . . . . . . . . . 29 The Fields Editor . . . . . . . . . . . . . . . . . 31 Adding fields to a data set. . . . . . . . . . . . 31 TField component properties . . . . . . . . . . 33 Defining a calculated field . . . . . . . . . . . 38 Lists and lookups. . . . . . . . . . . . . . . . . 44 Setting a TQuerys SQL property . . . . . . . 48 Defining a query parameter . . . . . . . . . . 49 Delphi Data Access components hierarchy . . . . . . . . . . . . . . . . . . . . . . 56 Dataset state diagram . . . . . . . . . . . . . . 59 Field Link designer . . . . . . . . . . . . . . . . 76 Fields Editor . . . . . . . . . . . . . . . . . . . . 80 Fields Editor Add Fields dialog box . . . . . . 81 Define Field dialog box . . . . . . . . . . . . . 82 Input Mask Editor . . . . . . . . . . . . . . . . 84 Sample form . . . . . . . . . . . . . . . . . . . . 94 Two forms . . . . . . . . . . . . . . . . . . . . . 95 Data Controls Component palette . . . . . . . 99 TDBText component . . . . . . . . . . . . . . 102 TDBEdit component at design time . . . . . 102 TDBGrid component. . . . . . . . . . . . . . 103 TDBNavigator component . . . . . . . . . . 106 TDBMemo component. . . . . . . . . . . . . 108 DBImage component. . . . . . . . . . . . . . 108 DBComboBox component . . . . . . . . . . 109 TDBListBox component . . . . . . . . . . . . 110 TDBLookupCombo component . . . . . . . 111 TDBLookupList component . . . . . . . . . 113 TDBCheckBox component . . . . . . . . . . 113 4.13 A TDBRadioGroup component . . . . . . . . 114 5.1 TQuery methods and flow . . . . . . . . . . . 117 5.2 Editing SQL statements in the String List Editor . . . . . . . . . . . . . . . . . . . . . 118 5.3 Working in the Visual Query Builder . . . . 119 5.4 Parameters Editor . . . . . . . . . . . . . . . . 121 5.5 Form with linked queries. . . . . . . . . . . . 123 6.1 InterBase parameters in the String List Editor . . . . . . . . . . . . . . . . . . . . . . . 132 6.2 Database Login dialog box. . . . . . . . . . . 133 6.3 Database Properties Editor. . . . . . . . . . . 134 6.4 TStoredProc Parameters Editor . . . . . . . . 139 A.1 The Database Desktop application window . . . . . . . . . . . . . . . . . . . . . . 148 A.2 Application window tool bar . . . . . . . . . 148 A.3 A table . . . . . . . . . . . . . . . . . . . . . . . 150 A.4 Table Type dialog box . . . . . . . . . . . . . 151 A.5 The Create Table dialog box . . . . . . . . . . 151 A.6 The Create Table dialog box for SQL tables . . . . . . . . . . . . . . . . . . . . . . . . 155 A.7 The Define Index dialog box for SQL indexes. . . . . . . . . . . . . . . . . . . . . . . 156 A.8 Save Index As dialog box. . . . . . . . . . . . 156 A.9 Referential integrity . . . . . . . . . . . . . . . 157 A.10 Referential Integrity dialog box . . . . . . . . 158 A.11 The Restructure Table dialog box for Paradox tables . . . . . . . . . . . . . . . . . . 160 A.12 The Restructure Table dialog box for SQL tables. . . . . . . . . . . . . . . . . . . . . 160 A.13 The Table window tool bar . . . . . . . . . . 161 A.14 A scroll lock in the Table window . . . . . . 162 A.15 Hot zone pointers in the Table window . . . 163 A.16 The Customer table in Edit mode . . . . . . . 164 A.17 The SQL Editor. . . . . . . . . . . . . . . . . . 167 A.18 The SQL Editor and an Answer table . . . . . 168 A.19 SQL Editor Toolbar . . . . . . . . . . . . . . . 168 A.20 SQL statement in the SQL Editor . . . . . . . 169 A.21 A query and its results . . . . . . . . . . . . . 170 B.1 BDE Configuration Utility main window . . 171 B.2 Sample Add New Alias dialog box. . . . . . 172 B.3 Customizing the new alias . . . . . . . . . . . 172 B.4 BDE non-system configuration dialog box . . . . . . . . . . . . . . . . . . . . . 173
vi