在这一章里我们主要介绍Delphi的数据访问部件的层次结构、多部件之间的关系、部件的属性、方法、事件以及各部件的应用。这些部件包括:
● TSession部件
● 数据集部件(TTable和TQuery)
● TDatasource部件
● 字段对象TField
● 字段编辑器的使用
● TReport部件和TBatchMove部件
我们对这些部件的属性、方法和事件进行一般性的描述,读者在实际使用Delphi开发应用程序时,还可以通过联机帮助获得有关部件更详细的信息。
15.1 Delphi数据访问部件的层次结构
Delphi提供了强大的开发数据库应用程序的能力,它给用户提供了大量的数据访问部件。以方便程序设计人员开发数据库应用程序。这些部件中,有些部件继承了另一些部件的属性、方法和事件,也就是说多部件之间存在着继承和被继承的关系,各部件的这种关联便构成了一个层次结构
图15.1 Delphi数据访问部件的层次结构
TSession是全局性的部件,在应用程序运行时,它自动地建立,在设计阶段和运行过程中它是一个不可见的部件。
TDatabase部件是为开发客户/服务器数据库应用程序时,设置登录的数据库的有关参数的,它在数据访问部件页上。
TDataset部件是不可见的,TTable和TQuery部件是由它派生而来的,这两个部件一般被称为数据集部件,它们在数据访问部件页上。
TDatasource部件是连接数据集部件和数据浏览部件的桥梁,它在数据访问部件页上。
TFields部件对应于数据库表中的实际字段,它既可以在应用程序的运行过程中动态地生成也可以在程序设计阶段用字段编辑器创建。它是不可见的部件,在程序中我们可以通过TField部件来访问数据库记录的各个字段值。
15.2 Tsession部件及其应用
TSession部件一般用得较少,但它对于一些特殊的应用是很有用的,在每一个数据库应用程序运行时Delphi自动地创建一个TSession部件。程序设计人既不能看见该部件也不能显示地创建一个TSession 部件,但是我们可以在应用程序中全局性地使用TSession部件的属性、方法。
15.2.1 TSession部件的重要属性及作用
TSession部件的许多重要属性是用于控制数据库应用程序与数据库的连接的,在一个应用程序中,可以全局性地设置TSession的有关属性值,对与之相连接的磁盘上的数据库进行控制。TSession部件主要有下列属性:
Database属性:是TSession中可以进行连接的所有数据库的数据库名字列表,这些数据库的名字常常是实际数据库的别名,包括数据库的路径、用户名、用户登录口令等参数。
DatabaseCount属性:是TSession中可以进行连接的所有数据库的数量,它是一个整数。
KeepCounnections属性:是一个布尔型属性,用它说明应用程序是否保持与一个非活动数据库的连接。因为对于一个数据库,当该数据库中没有相应的数据集部件(TTable或TQuery)被打开时,该数据库将自动地变成非活动的数据库。缺省情况下,KeePcounnections的值是True,就是说应用程序总是保持着与数据库的连接,即使数据库变成了非活动的数据库时,也是如此。如果将KeepConnections属性设置成False,那么当数据库由活动状态变成非活动状态时,应用程序与该数据库的连接也随之中断。
NetFileDir属性:说明BDE网络控制文件的路径名。
PrivateDir属性:说明存取临时文件的路径名。
15.2.2 TSession部件的方法:
TSession部件中的大部分方法是用于向用户提供与应用程序相连接的数据库的信息,如数据库的名字及别名,数据库中的表名以及数据库引擎BDE的有关参数等,在设计数据库应用程序时,想要获取有关数据库的信息,调用TSession部件的下列方法,将会大大简化程序的设计。
GetAliasNames方法:调用该方法,我们可以获得数据库引擎BDE中定义的数据库别名。
GetAliasParams方法:该方法主要用于获取我们在BDE中定义数据库别名时所说明的参数值,如BDE所在的目录路径以及实际名称等。
GetDatabaseNames 方法:调用该方法可以帮助我们获得当前应用程序可以进行连接的所有数据库的名字,数据库的名字是用户使用BDE工具定义的实际数据库的别名。
GetDriverNames方法:数据库引擎BDE可以与多种数据库管理系统相连接,如客户/服务器数据库管理系统Oracle、Sybase以及本地数据库管理系统dBASE,Paradox等,BDE与每一种数据库管理系统进行连接时,都有相应的驱动程序,而且这些驱动程序都可以选择地安装。通过调用GetDriverNames方法。我们可以获得当前BDE安装的数据库驱动程序的名字。
GetDriverParams方法:BDE的数据库驱动程序中包含着多个参数,如支持的民族语言、DBMS的版本号、文件块大小等,对于服务器上的DBMS,还有数据库服务器的名字等等。
GetTableNames方法:因为每一个数据库都是由多个数据库表组成的,我们通过说明数据库名,然后调用GetTableNames方法,便可以获得该数据库中全部的数据库表的名字。
上述这些方法在调用时都需要一个字符串列表作为参数,而且都返回一个字符串列表的值。
TSession部件还有一个叫DropConnections的方法用于控制应用程序与数据库的连接,当调用DropConnections方法时,应用程序与所有的数据库的连接将会切断。
15.2.3 TSession部件应用举例
例15.1:我们创建一个应用程序,通过调用TSession有关的方法获取当前应用程序可以进行连接的数据库的名字以及获取其中任意一个数据库中的全部数据库表的名字。
通过TSession部件获取数据库的有关信息
窗体中主要使用了两个列表框,其中列表框DatabaselistBox用于显示数据库的名字,列表框TablelistBox用于显示数据库中的表名。程序运行完后数据库的名字显示在DatabaselistBox列表框中,当用户单击DatabaselistBox列表框中的数据库名时,该数据库全部的数据库表的名字将会显示在TablelistBox列表框中。有关的程序代码如下:
程序清单15.1
unit unit31; interface usesSysUtils, Windows, Messages, Classes, Graphics, Controls,Forms, Dialogs, StdCtrls, DB, DBTables, Buttons, ComCtrls, Tabnotbk; type TQueryForm = class(TForm)BitBtn1: TBitBtn;DataSource1: TDataSource;Table1: TTable;GroupBox1: TGroupBox;CheckBox1: TCheckBox;CheckBox2: TCheckBox;PageControl1: TPageControl;TabSheet1: TTabSheet;Label1: TLabel;Label2: TLabel;Label3: TLabel;ListBox1: TListBox;ListBox2: TListBox;ListBox3: TListBox;TabSheet2: TTabSheet;Memo1: TMemo;procedure FormCreate(Sender: TObject);procedure ListBox1Click(Sender: TObject);procedure ListBox2Click(Sender: TObject);end;varQueryForm: TQueryForm;implementation{$R *.DFM}uses RSLTFORM;procedure TQueryForm.FormCreate(Sender: TObject);beginScreen.Cursor := crHourglass;{ Populate the alias list }with ListBox1 dobeginItems.Clear;Session.GetAliasNames(Items);end;{ Make sure there are aliases defined }Screen.Cursor := crDefault;if ListBox1.Items.Count 1 thenMessageDlg( 'There are no database aliases currently defined. You ' +'need at least one alias to use this demonstration.',mtError, [mbOK], 0 );end;procedure TQueryForm.ListBox1Click(Sender: TObject);varstrValue: string; { Holds the alias selected by the user }bIsLocal: Boolean; { Indicates whether or not an alias is local }slParams: TStringList; { Holds the parameters of the selected alias }iCounter: Integer; { An integer counter variable for loops}begin{ Determine the alias name selected by the user }with ListBox1 dostrValue := Items.Strings[ItemIndex];{ Get the names of the tables in the alias and put them in theappropriate list box, making sure the user's choices are reflectedin the list. } ListBox2.Items.Clear;Session.GetTableNames(strValue, { alias to enumerate }'', { pattern to match }
15.3.4 数据集中的数据维护
数据集中的数据维护主要包括数据记录的修改,插入和删除。Delphi为数据集部件提供了相应的方法用于其中的数据维护。这些方法如表15.所示。
表15.3 Delphi用于数据维护的方法
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
方 法 名 功 能
──────────────────────────────
Edit 将数据集置为编辑状态
──────────────────────────────
Append 投寄所有被修改的记录,将记录指针移到表中的最后
一条记录,且将数据集置为插入状态
──────────────────────────────
Insert 投寄所有被修改的记录将数据集置为插入状态
──────────────────────────────
Post 将插入的新记录和修改的记录写回磁盘上的数据库表,
即投寄,当投寄成功时数据集回到浏览状态,若投寄
不成功数据集仍然保持原有状态
──────────────────────────────
Cancel 取消当前的操作且将数据集置为浏览状态
──────────────────────────────
Delete 删除当前记录指针所在的记录且将数据集置为浏览状态
──────────────────────────────
AppendRecord 在表的最后插入一条新记录,记录的各个字段值作为
AppendRecord的参数传递给新记录
──────────────────────────────
InsertRecord 在当前指针所在记录的后面插入一条新记录, 记录的
各个字段值作为InsertRecord的参数传递给新记录。
──────────────────────────────
SetRecords 修改当前记录,字段名和相应的字段值作为SetRecords
的参数
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Edt方法:如果应用程序想对数据集中的数据记录进行修改,我们必须要将数据集设置成编辑状态。调用数据集部件的Edit方法便可以将数据集置成编辑状态,当数据集已经处在编辑状态时,调用Edit方法不会产生作用。当数据集处于编辑状态时,移动记录指针或调用post方法都可以将当前记录的修改写回到磁盘数据库表中。在程序中, Edit方法和post方法常常配合在一起使用,用于修改表中的记录。如:
Table1.Edit;Tabel1.FieldByName('CustNo').Asstring := '1234';Table1.st;
在上述这一段程序代码中,第一行程序是将Table1置成编辑状态,第二行程序是对当前记录指针所在的记录的CustNo字段的值修改成'1234',第二行程序是调用post方法将对当前记录的修改写回数据库表。
Append方法和Insert 方法:这两个方法都是将数据集部件置成插入状态,以在表中插入新记录,Insert方法是在当前指针位置的记录后面插入一打新记录,Append方法是在表的尾部插入一打新记录,不过这要注意,无论用户是调用Insert方法还是Append方法插入新记录,增加记录到一个具有索引的表中时,都是按照索引顺序写入其位置,也就是说对于索引表格Insert方法和Append方法的作用是一样的,Append仅适用于没有索引的表。Insert方法和Append方法实际上是将数据集置成插入状态,并且插入一条空白记录,要真正插入一条新记录,我们必须在调用Insert或Append方法之后,还要给新记录的各个字段赋值,最后调用post方法,将插入的记录写回数据库表。调用这两种方法插入新记录的一般步骤如下:
With tabe1 DOBeginInsert; {调用Insert方法,插入一条空记录}<为记录的各字段赋值>Post;End;
Post方法:数据集中的记录被修改或插入新记录时调用post方法将数据集的修改写回到数据库表。根据数据集所处的状态不同,post方法所产生的作用和效果是不一样的:
● 当数据集处于编辑状态时,调用post方法,将当前记录的修改写回数据库表
● 当数据集处于插入状态时,调用post方法,将插入的新记录写回数据库表
● 当数据集处于SetKey状态时,调用post方法,将数据集置成浏览状态(Browse状态)
post方法的调用既可以显式地调用,也可以隐含地调用,当数据集处于编辑状态或插入状态时,当移动记录指针时,Delphi会隐含地调用post方法,将将当前记录的修改写回数据库表,在程序调用Insert方法或Append方法时,也会隐含地调用Post方法,将先前的数据集的修改写回数据库表。
Delete方法:Delete方法用于删除表中的记录,调用Delete方法时,将会删除表中当前的记录,并且自动地将记录指针移到被删记录的下一条记录,同时将数据集置成Browse状态。
Cancel方法:Cancel方法用于取消当前的操作,当程序还没有调用Post方法,将对记录的修改写回数据库表时,调用Cancel方法,可以将记录恢复到没有修改之前的状态。并且在调用Cancel方法时,它总是将数据集置成Browse状态。
AppendRecord方法和InsertRecord方法:这两个方法分别与Append方法和Insert方法相似。它们都是用于在表中插入一条新记录,但AppendRecord方法和InsertRecord方法比Append和Insert方法更简单更方便一些,它们直接在表中插入一条新记录,新记录的各个字段值作为AppendRecord或InsertRecord方法的参数传递给新记录并且不需显式地调用post方法,将插入的新记录写回数据库表。在给插入的新记录赋字段值时,将由多个字段值组成的数组作为AppendRecord或InsertRecord的参数,在字段值数组中可以为每一个字段提供一个值,或从左边一列开始依次为任意多个字段赋值。也就是说,用户可以从数据库表的最左一列起,把许多列的值同时传递给InsertRecord,直到所有的字段被赋值,用户也可以省略字段序列后面的的一些字段值,InsertRecord会用空值来填充这些字段:用户也可以对那些明确希望用空填充的字段传递保留字NIl。
例如:如果表Country有Name,Captial,Continent,Area和Population字段,并且数据集部件Table1与它相连,下面的代码便可以在Country表中当前记录的后面插入一条新记录。
Table1.InsertRecord (["中国","北京","五洲"]);
在上述代码中没有为Area和population字段赋值,InsertRecord会用空值来填这两个字段。
SetRecords方法:调用该方法可以修改表中当前记录的多个字段的值,调用该方法之前必须将数据集部件置成编辑状态,调用该方法之后,还要调用post方法,才能真正将当前记录的修改写回数据库表。调用SetRecord方法时,被修改的字段值必须要与表中实际存在的字段名对应,并且数据类型要相匹配。例如,下面的代码是修改上面刚刚插入的那条记录。
(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)
Table1.Edit;Tabel1.SetRecord(, , ,9600000,1200000000);Tabel1.post;
这一段代码是修改上面刚刚插入的那条记录的Area 和Population 字段的值,而对Name,Continent和Captial字段没有修改。
在数据集部件中,还有一个重要方法Abort方法,该方法是用于取消其他方法的调用的,如在插入记录、修改记录和删除记录之前,往往需要用户确认是否真的要执行这种操作,此时调用Abort方法便可取消各种方法的调用,下面的代码是在用户删除一条记之前,让用户确认是否真的要执行删除操作。
Tabel1.BeforeDelete(DataSet:TDataSet);
If MessageDlg('真的要删除记录吗?',
mtConfirmation,mbyesNoCanel,0 mryes then
Abort; {取消删除操作}
关于书签(BookMark)操作;
书签操作主要用于在表中快速地定位记录指针,在应用程序中常常要保存记录指针所在的位置,在进行其他处理之后,希望能快速地返回到先前指针所在的位置,此时,使用书签将显得特别有用。有关书签操作,Delphi提供了三个方法,它们是:
● GetBookMark
● GotoBookMark
● FreeBokMark
这三个方法一般都是在一起使用,GetBookMark方法返回一个TBookMark类型的变量,该变量包含着指向当前记录的指针,GotoMark方法用于快速地将记录指针定位到具有书签的记录处。FreeBookmark方法是与GetBookMark方法相反的操作,它释放书签标志。下面的程序代码阐述了书签操作的一般方法:
BookMark : TBookMark;Do somethingBookMark := Table1.GetBookMark; {对当前记录作书签标志}Table1.DisalbeControls; {切断Table1与数据察觉部件的联系}Table.FirstWhile Not EOF Do {对表中全部记录进行其他处理}beginDo somethingTabel1.Next;end;Tabel1.GotoBookMark(BookMark) Table1.enableControls; {重新定位记录指针回到原来的位置}Tabel1.FreeBookMark(BookMark); {删除书签BookMark标志}
15.3.5 数据集部件与数据浏览部件的连接
数据集部件TTabel和TQuery具有三个方法,DisableControls 方法、EnableControls方法、Refresh方法用于控制数据集部件和与其相连的数据浏览部件之间的连接,以及控制数据浏览部件的显示。在用户修改和更新以及遍历数据库表中的记录时,调用DisableControls方法具有重要意义,调用DisbaleControls方法以切断TTable或TQuery部件与数据浏览部件的连接,使数据浏览部件暂时失效,否则,在对TTable或TQuery部件的每次修改之后,窗体中所有与它们相连的数据浏览部件都要更新其显示内容,这亲显然会减慢处理速度。当遍历表中的记录时记录指针每移动一下,窗体中的数据浏览部件也随之更新一下其中的显示内容,在屏幕上产生闪烁。
EnableControls方法的作用与DisbaleControls方法的作用是相反的,调用EnableControls方法,使TTable或TQuery部件恢复与数据浏览部件的连接,使暂时失效的数据浏览部件恢复到正常显示表中记录信息的状态。
Refresh方法用于刷新数据浏览部件中的显示。在调用Refresh方法时,必须要确保TTable或TQuery部件是打开的。当数据集中的记录被修改之后,调用Refresh方法,数据浏览部件中显示的信息也随之改变。
15.3.6 数据集部件的事件
数据集部件TTable或TQuery具有很多的事件。为这些事件编写相应的程序代码可以进行有效性验证、计算可计算字段的值、确认对数据库表的多种操作等等。这些事件及其描述如表15.4所示。
表15.4 数据集部件常用的事件
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
事 件 描 述
───────────────────────────────────
(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)BeforeOpen,Afteropen 在数据集部件被打开之前/之后被触发
───────────────────────────────────
(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)BeforeClose,Afterclose 在数据集部件被关闭之前/之后被触发
───────────────────────────────────
(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)BeforeInsert,AfterInsert 在数据集部件进入插入状态之前/之后被触发
───────────────────────────────────
(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)BeforeEdit,AfterEdit 在数据集部件被编辑之前/之后被触发
───────────────────────────────────
(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)BeforePost,AfterPost 在数据集部件投寄被修改的记录之前/之后被触发
───────────────────────────────────
(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)BeforeCancel,AfterCancel 在数据集部件取消前一步操作之前/之后被触发
───────────────────────────────────
(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)BeforeDelete,AfterDelete 在数据集部件删除当前记录之前/之后被触发
───────────────────────────────────
(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)OnNewRecord 当建立一条新记录时被触发
───────────────────────────────────
(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)OnCalcFields 当为表中的计算字段计算字段值时被触发
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
15.4 TTable部件及应用
在前一节里我们介绍了数据集部件TTable 和TQuery 的共同的一些属性和方法。TTable部件是Delphi数据库编程中要经常使用的最重要的部件之一,它是数据库应用程序访问数据库时必须使用的数据集部件之一,在这一节里,我们重点介绍TTable部件特有的属性和方法,TTable部件所有的属性、方法和事件都可以在联机帮助中查到。
15.4.1 TTabel部件主要的属性
DatabaseName属性和TableName属性:
DatabaseName属性是说明数据库应用程序所操作的数据库的名字,它可以是由BDE定义的数据库的别名、显式说明的数据库文件所在的磁盘路径或者由TDatabase部件定义的一个数据库名。DatabaseName属性常常是一个由BDE定义的数据库的别名。使用由BDE定义的数据库的别名代替数据库实际所在的路径和名字,好处是当实际的数据库存放的位置发生变化时,只需利用BDE简单地设置一下该数据库的别名,而数据库应用程序无需修改。有关BDE的使用请参看BDE的设置应用。TabelName属性用以说明当前TTable部件所连接的实际的数据库表。这两个属性一般都在设计阶段指定,当然在程序运行过程中也可以设置,但是要修改这两个属性时,必须要在TTabel的Active属性为False时进行,当TTable的Active属性为True时,这两个属性是不能被修改和设置的。