1. Trang chủ
  2. » Công Nghệ Thông Tin

MASTERING DELPHI 6 phần 6 pptx

108 173 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 108
Dung lượng 714,89 KB

Nội dung

536 Both find methods use as parameters an array of constants. Each array element corre- sponds to one of the fields of the current index. You can also pass only the value for the initial field or fields of the index, so the following fields will not be considered. NOTE I won’t discuss these features in details, showing complete examples, because some of them are limited to the BDE and makes sense only for local tables, not for SQL server–based tables. Actually if you set a filter or a range over a Table connected with a SQL server, the BDE will try to generate a proper select statement, avoiding fetching all the data and filtering it locally. The problem is that this isn’t always possible and you lose most of your control, two good reasons to use the Query component when working with SQL servers. A Query with Parameters When you need slightly different versions of the same SQL query, instead of modifying the text of the Query (stored in the SQL property) each time, you can write a query with a parame- ter and simply change the value of the parameter. For example, if you decide to have a user choose the countries of a continent (using the Country table of the DBDEMOS database), you can write the following parametric query: select * from Country where Continent = :Continent In this SQL clause, :Continent is a parameter. We can set its data type and startup value, using the editor of the Params property collection of the Query component. When the Parameters collection editor is open, as shown in Figure 13.1, you see a list of the parameters defined in the SQL statement and set the data type and the initial value of these parameters. The form displayed by this program, called ParQuery and available on the companion CD, uses a list box to provide all the available values for the parameters. Instead of preparing the items of the list box at design time, we can extract the available continents from the same FIGURE 13.1: Editing the collection of parameters of a Query component Chapter 13 • Delphi’s Database Architecture Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com 537 database table as the program starts. This is accomplished using a second query component, with this SQL statement: select distinct Continent from Country After activating this query, the program scans its result set, extracting all the values and adding them to the list box: procedure TQueryForm.FormCreate(Sender: TObject); begin // get the list of continents Query2.Open; while not Query2.EOF do begin ListBox1.Items.Add (Query2.Fields [0].AsString); Query2.Next; end; ListBox1.ItemIndex := 0; // open the first query Query1.Params[0].Value := ListBox1.Items [0]; Query1.Open; end; Before opening the query, the program selects as its parameter the first item of the list box, which is also activated by setting the ItemIndex property to 0. When the list box is selected, the program closes the query and changes the parameter: procedure TQueryForm.ListBox1Click(Sender: TObject); begin Query1.Close; Query1.Params[0].Value := ListBox1.Items [Listbox1.ItemIndex]; Query1.Open; end; This displays the countries of the selected continent in the list box, as you can see in Figure 13.2. The final refinement is that when the user enters a record with a new continent, it is added automatically to the list box. Instead of refreshing the entire list, with the same code executed in the FormCreate method, we can do this by handling the BeforePost event and adding the continent to the list if it is not already there: procedure TQueryForm.Query1BeforePost(DataSet: TDataSet); var StrNewCont: string; begin // add the continent, if not already in the list StrNewCont := Query1.FieldByName (‘Continent’).AsString; if ListBox1.Items.IndexOf (StrNewCont) < 0 then ListBox1.Items.Add (StrNewCont); end; Classic BDE Components Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com 538 We can add a little extra code to this program to take advantage of a specific feature of parameterized queries. To react faster to a change in the parameters, these queries can be optimized, or prepared. Simply call the Prepare method before the program first opens the query (after setting the Active property of the Query component to False at design time) and call Unprepare once the query won’t be used anymore: procedure TQueryForm.FormCreate(Sender: TObject); begin // prepare and open the first query Query1.Prepare; Query1.Params[0].Value := ListBox1.Items [0]; Query1.Open; end; procedure TQueryForm.FormDestroy(Sender: TObject); begin Query1.Close; Query1.Unprepare; end; Prepared parameterized queries are very important when you work on a complex query. In fact, the BDE or the SQL server must read the text of the query and determine how to process it. If you use the same query (even if a parametric one) over and over, the engine doesn’t need to reprocess the query but already knows how to handle it. Master/Detail Structures Often you need to relate tables, which have a one-to-many relationship. This means that for a single record of the master table, there are many detailed records in a secondary table. A classic example is that of an invoice and the items of the invoice; another is a list of customers FIGURE 13.2: The ParQuery example at run time Chapter 13 • Delphi’s Database Architecture Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com 539 and the orders each customer has made. This is very common situation in database program- ming, and Delphi provides explicit support for it with the master/detail structure. We’ll see this structure for BDE Table and Query components, but the same technique applies to almost all of the datasets available in Delphi. NOTE The TDataSet class has a generic DataSource property for setting up a master data source, but the Table component, for example, uses a different property (MasterSource) to express the same concept. Master/Detail with Tables The simplest ways to create a master/detail structure in Delphi is to use the Database Form Wizard, selecting a master/detail form in the first page. To accomplish the same effect manu- ally, place two table components in a form or data module, connect them with the same data- base, and connect each with a table. In the MastDet example, I’ve used the customer and orders tables of the DBDEMOS database, and I’ve used a data module. Now add a DataSource com- ponent for each table, and for the secondary table set a master source to the data source con- nected to the first table. Finally relate the secondary table to a field (called MasterField) of the main table, using the special property editor provided. A Data Module for Data-Access Components To build a Delphi database application, you can place data-access components and the data- aware controls in a form. This is handy for a simple program, but having the user interface and the data access and data model in a single, often large, unit is far from a good idea. For this reason, Delphi implements the idea of data module, a container of nonvisual components I already introduced in Chapter 1, “The Delphi 6 IDE.” At design time, a data module is similar to a form, but at run time it exists only in memory. The TDataModule class derives directly from TComponent, so it is completely unrelated to the Win- dows concept of a window (and is fully portable among different operating systems). Unlike a form, a data module has just a few properties and events. For this reason, it’s useful to think of data modules as components and method containers. Like a form or a frame, a data module has a designer. This means Delphi creates for a data module a specific Object Pascal unit for the definition of its class and a form definition file that lists its components and their properties. There are several reasons to use data modules. The simplest one is to share data-access com- ponents among multiple forms, as I’ll demonstrate at the beginning of the next chapter. This technique works in conjunction with visual form linking, the ability to access components of another form or data module at design time (with the File ➢Use Unit command). The second Classic BDE Components Continued on next page Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com 540 reason is to separate the data from the user interface, improving the structure of an applica- tion. Data modules in Delphi even exist in versions specific for multitier applications (remote data modules) and server-side HTTP applications (Web data modules). Finally, remember that you can use the Diagram page of the editor, introduced in Chapter 1, to see a graphical representation of the connections among the components of a data module, as you can see in this example for the MastDet application: The following is the complete listing (only without the irrelevant positional properties) of the Data Module used by the MastDet program on the CD: object DataModule1: TDataModule1 OnCreate = DataModule1Create object TableCust: TTable DatabaseName = ‘DBDEMOS’ TableName = ‘customer.db’ end object TableOrd: TTable DatabaseName = ‘DBDEMOS’ IndexName = ‘CustNo’ MasterFields = ‘CustNo’ Chapter 13 • Delphi’s Database Architecture Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com 541 MasterSource = dsCust TableName = ‘orders.db’ end object dsCust: TDataSource DataSet = TableCust end object dsOrd: TDataSource DataSet = TableOrd end end TIP Starting with Delphi 5, you can also create a master/detail structure using the Data Diagram view of a data module. In Figure 13.3 you can see an example of the main form of the MastDet program at run time. I’ve placed data-aware controls related to the master table in the upper portion, and I’ve placed a grid connected with the detail table in the lower portion of the form. This way, for every master record, you immediately see the list of the connected detail record, in this case all the orders by the current client. Each time you select a new customer, the grid below displays only the orders pertaining to that customer. A Master/Detail Structure with Queries The previous example used two tables to build a master/detail form. As an alternative, you can define this type of join using a SQL statement. After setting the master DataSource for FIGURE 13.3: The MastDet example at run time Classic BDE Components Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com 542 the detailed query, you simply set up its SQL statement with a parameter having the same name of the field of the master dataset this data source refers to. For this example (called Orders), I’ve joined the ORDERS.DB table with ITEMS.DB, which describes the items of each order. The two tables can be joined using the OrderNo field. When you generate the code, the program behaves exactly like the previous one, Mast- Det. This time, however, the trick is in the SQL statements of the second query object: select OrderNo, ItemNo, PartNo, Qty from items where OrderNo = :OrderNo As you can see, this SQL statement uses a parameter, OrderNo. This parameter is con- nected directly to the first query, because the DataSource property of QueryItems is set to dsOrders, which is connected to QueryOrders. In other words, the second query is considered to be a data control connected to the first data source. Each time the current record in the first data source changes, the QueryItems component is updated, just like any other compo- nent connected to dsOrders. The field used for the connection, in this case, is the field hav- ing the same name as the query parameter. Other BDE Related Components Along with Table, Query, StoredProc, and DataSource, other components are on the Data Access page of the Component palette, the BDE page. I’ll cover these components in the next chapter, but here is a short summary: • The Database component is used for transaction control, security, and connection con- trol. It is generally used only to connect to remote databases in client/server applica- tions or to avoid the overhead of connecting to the same database in several forms. The Database component is also used to set a local alias, one used only inside a program. Once this local alias is set to a given path, the Table and Query components of the application can refer to the local database alias. This is much better than replicating the hard-coded path in each DataSet component of the program. TIP The Borland Database Engine (BDE) uses an alias to refer to a database file or directory. You can define new aliases for databases by using the Database Explorer or the Database Engine Configuration utility. It is also possible to define them by writing code in Delphi that calls the AddStandardAlias and AddAlias methods of the Session global object, followed by a call to SaveConfigFile to make the alias persistent. The alternative is the low-level DbiAddAlias BDE function. In some of the program of this chapter I’ll use the DBDEMOS database alias, which refers to Delphi’s demo database, installed by default in the C:\Program Files\Common Files\Borland Shared\Data directory. Chapter 13 • Delphi’s Database Architecture Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com 543 • The Session component provides global control over database connections for an application, including a list of existing databases and aliases and an event to customize database login. • The BatchMove component is used to perform batch operations, such as copying, appending, updating, or deleting values, on one or more databases. • The UpdateSQL component allows you to write SQL statements to perform various update operations on the dataset, when using a read-only query (that is, when working with a complex query). This component is used as the value of the UpdateObject prop- erty of tables or queries. Using Data-Aware Controls Once you’ve set up the proper data-access components, you can build a user interface to let a user view the data and eventually edit it. Delphi provides many components that resemble the usual Windows controls but are data-aware. For example, the DBEdit component is sim- ilar to the Edit component, and the DBCheckBox component corresponds to the CheckBox component. You can find all of these components in the Data Controls page of the Delphi Component palette. All of these components are connected to a data source using the corresponding property, DataSource. Some of them relate to the entire dataset, such as the DBGrid and DBNavigator components, while the others refer to a specific field of the data source, as indicated by the DataField property. Once you select the DataSource property, the DataField property will have a list of values available in the drop-down combo box of the Object Inspector. NOTE In Chapter 18, “Writing Database Components,” we’ll discuss the technical details of these controls, as we’ll see how to write custom data-aware components. Notice that all the data-aware components are totally unrelated to the data-access technol- ogy, provided the data-access component inherits from TDataSet. This means that your investment on the user interface is totally preserved when you change the data-access tech- nology. What is true, however, is that some of the lookup components and an extended use of the DBGrid, displaying a lot of data, only make more sense when working with local data, and should generally be avoided in a client/server situation, as we’ll see in the next chapter. Data in a Grid The DBGrid is a grid capable of displaying a whole table at once. It allows scrolling and navi- gation, and you can edit the grid’s contents. It is an extension of the other Delphi grid controls. Using Data-Aware Controls Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com 544 You can customize the DBGrid by setting the various flags of its Options property and modifying its Columns collection. The grid allows a user to navigate the data, using the scroll- bars, and perform all the mayor actions. A user can edit the data directly, insert a new record in a given position by pressing the Insert key, append a new record at the end by going to the last record and pressing the Down arrow key, and delete the current record by pressing Ctrl+Del. The Columns property is a collection where you can choose the fields of the table you want to see in the grid and set column and title properties (color, font, width, alignment, caption, and so on) for each field. Some of the more advanced properties, such as ButtonStyle and DropDownRows, can be used to provide custom editors for the cells of a grid or a drop-down list of values (indicated in the PickList property of the column). An alternative to the DBGrid is the DBCtrlGrid component, a multirecord grid that can host panels with other data-aware controls. These controls are duplicated in each panel for each record of the dataset. I’ll discuss the DBCtrlGrid control at the end of this chapter. DBNavigator and Dataset Actions DBNavigator is a collection of buttons used to navigate and perform actions on the database. You can disable some of the buttons of the DBNavigator control, by removing some of the elements of the VisibleButtons set. The buttons perform basic actions on the connected dataset, so you can easily replace them with your own toolbar, particularly if you use an ActionList component with the predefined database actions provided by Delphi. In this case, in fact, you get all the standard behaviors, but you’ll also see the various buttons enabled only when their action is legitimate. TIP If you use the standard actions, you can avoid connecting them to a specific DataSource com- ponent, and the actions will be applied to the dataset connected to the visual control that cur- rently has the input focus. This way a single toolbar can be used for multiple datasets displayed by a form. Text-Based Data-Aware Controls There are multiple text-oriented components: • DBText displays the contents of a field that cannot be modified by the user. It is a data- aware Label graphical control. It can be very useful, but users might confuse this con- trol with the plain labels that indicate the content of each field-based control. Chapter 13 • Delphi’s Database Architecture Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com 545 • DBEdit lets the user edit a field (change the current value) using an Edit control. At times, you might want to disable editing and use a DBEdit as if it were a DBText, but highlighting the fact that this is data coming from the database. • DBMemo lets the user see and modify a large text field, eventually stored in a memo or BLOB (binary large object) field. It resembles the Memo component and has full edit- ing capabilities, but all the text is rendered in a single font. • DBRichEdit is a component that lets the user edit a formatted text file; it is based on a RichEdit Windows common control and, in contrast to DBMemo, it allows text with multiple fonts and paragraph styles. List-Based Data-Aware Controls For letting a user choose a value in a predefined list (which reduces input errors), you can use many different components. DBListBox, DBComboBox, and DBRadioGroup are similar, providing a list of strings in the Items property, but they do have some differences: • The DBListBox component allows selection of predefined items (“closed selection”), but not text input, and can be used to list many elements. Generally it’s best to show only about six or seven items, to avoid using up too much space on the screen. • The DBComboBox component can be used both for closed selection and for user input. The csDropDown style of the DBComboBox, in fact, allows a user to enter a new value, besides selecting one of the available ones. The component also uses a smaller area of the form because the drop-down list is usually displayed only on request. • The DBRadioGroup component presents radio buttons (which permit only one selec- tion), allows only closed selection, and should be used only for a limited number of alternatives. A nice features of this component is that the values displayed can be exactly those you want to insert in the database, but you can also choose to provide some sort of mapping. The values of the user interface (some descriptive strings stored in the Items property) will map to corresponding values stored in the database (some numeric or character-based codes listed in the Values property). For example, you can map some numeric codes indicating departments to a few descriptive strings: object DBRadioGroup1: TDBRadioGroup Caption = ‘Department’ DataField = ‘Department’ DataSource = DataSource1 Items.Strings = ( ‘Sales’ ‘Accounting’ ‘Production’ ‘Management’) Using Data-Aware Controls Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com [...]... data Very large integers (64 bit) Text of arbitrary length Generally not used directly This is the base class of all the numeric field classes Generally not used directly The base class for the fields providing support for object relational databases A pointer to an object in an object relational database Whole numbers in the range of integers ( 16 bits) (New field type in Delphi 6) Supports the date/time... Note that Paradox AutoInc fields do not always work perfectly, as discussed in the next chapter Boolean value Arbitrary data with a large (up to 64 KB characters) but fixed size Date and time value Floating-point numbers (8 byte) (New field type in Delphi 6) A true binary-coded decimal (BCD), as opposed to the existing TBCDField type, which converted BCD values to the Currency type This field type... nicelooking lookup combo box probably won’t be very effective NOTE In Delphi 6, both the TDBLookupComboBox and TDBLookupListBox controls have a NullValueKey property, which indicates the shortcut that can be used to set the value to null, by calling the Clear method of the corresponding field Graphical Data-Aware Controls Finally, Delphi includes two graphical data-aware controls: • DBImage is an extension... data of a fixed length (up to 8192 bytes) Time value Arbitrary data, up to 64 KB characters Very similar to the TBytes-Field base class A field representing a variant data type, part of the ADO support A field representing a Unicode ( 16 bits per character) string Whole positive numbers in the range of words or unsigned integers ( 16 bits) The availability of any particular field type, and the correspondence... output of the Calc example Notice the Population Density calculated column, the ellipsis button, and the message displayed when you select it Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com 566 Chapter 13 • Delphi s Database Architecture Lookup Fields As an alternative to placing a DBLookupComboBox component in a form (discussed earlier in this chapter under “Using Lookup Controls”), we can also define... select the New Field command, obtaining the New Field dialog box (As an alternative in Delphi 5, it’s possible to use the Diagram page of the editor, drop the two tables there, and drag a lookup relation from the ORDERS table to the EMPLOYEE table, connecting the two in the resulting New Field dialog box In Delphi 6, though, the lookup relation button is still part of the Diagram page but doesn’t seem... procedure TForm2.SpeedButton2Click(Sender: TObject); begin ShowMessage (string (Table1 [‘Name’]) +’: ‘+ string (Table1 [‘Population’])); end; Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com 560 Chapter 13 • Delphi s Database Architecture When you access the value of a field, you can use a series of As properties to handle the current field value using a specific data type (if this is available; otherwise,... output of the FieldAcc example after the Center and Format buttons have been pressed Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com The Fields of a Dataset 561 A Hierarchy of Field Classes There are several field class types in VCL Delphi automatically uses one of them depending on the data definition in the database, when you open a table at run time or when you use the Fields editor at design...5 46 Chapter 13 • Delphi s Database Architecture Values.Strings = ( ‘1’ ‘2’ ‘3’ ‘4’) end A slightly different component is the DBCheckBox, used to show and toggle an option, corresponding to a Boolean field It is... datasets Graphic of arbitrary length A field representing a COM Globally Unique Identifier, part of the ADO support Continued on next page Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com 562 Chapter 13 • Delphi s Database Architecture TABLE 13.1 continued: The Subclasses of TField Subclass Base Class Definition TIDispatchField TInterfaceField A field representing pointers to IDispatch COM interfaces, . from a good idea. For this reason, Delphi implements the idea of data module, a container of nonvisual components I already introduced in Chapter 1, “The Delphi 6 IDE.” At design time, a data module. Delphi s Database Architecture Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com 539 and the orders each customer has made. This is very common situation in database program- ming, and Delphi. database alias, which refers to Delphi s demo database, installed by default in the C:Program FilesCommon FilesBorland SharedData directory. Chapter 13 • Delphi s Database Architecture Copyright

Ngày đăng: 12/08/2014, 21:20