1、当笔者决定更新本书时,很难相信从 Delphi 7 到 Delphi 2006 已经过了将近 4 年的时间。在这段时间中,Borland 的数据库访问技术也有了相当大的变化。首先让我们介绍本书的主题:dbExpress。dbExpress 从Delphi 7 的 2.0 版本发展到了 Delphi 2006 的 3.0 版,其中的变化除了更新对于各种数据库最新版本的支持之外,更重要的进步就在于执行效率不断地提升以及在 Win32、Linux 和.NET 环境中能够同时执行。在Borland 宣布未来将推出 Win64 的 Delphi 版本之后,我们也可以预料到未来 dbExpress 也将会
2、有 64 位的版本。除了这些之外,dbExpress 也有许多其他的进步。例如 dbExpress 开始加入支持 MSSQL Unicode 的能力,也可以处理返回结果数据集的存储过程,强化 MetaData 的支持能力,更高的执行存储过程效率,等等。简而言之,dbExpress 现在已经进化成 Delphi 中最重要的数据库访问技术了(见表 0-1) 。表 0-1Delphi 版本 dbExpress 版本Delphi 6 1.0Delphi 7 2.0Delphi 2005 2.5Delphi 2006 3.0除了 dbExpress 之外,Borland 在.NET 下基于 ADO.NE
3、T 的数据库访问技术 Borland Data Provider(BDP) ,也有着显著的进步。BDP 也和 dbExpress 一样,执行效率不断地提升。Delphi 2006 的 BDP 加入了连接池的功能,让 BDP 在连接、访问和服务大量客户端的情形下的执行效率比以前的版本增加了数倍(见表 0-2) 。表 0-2Delphi 版本 BDP 版本Delphi 8 1.0Delphi 2005 2.0Delphi 2006 3.0从 dbExpress 和 BDP 的进步幅度来看,Delphi Rlibcs.dllDelphi 2006 的 dbExpress 3.0 不但支持了更新的关系
4、数据库,而且比 dbExpress 1.x/2.x 版增加了 Adaptive Sybase Anywhere 以及 Sybase 的支持,此外,目前 dbExpress 对于 MySQL 的支持虽然只到 4.0.24,但是Borland 准备在不久的将来也支持最新的 MySQL 5.0。要学习 dbExpress 控件最好的方法就是直接使用它来开发数据库应用程序,在下一节我们将立刻进入学习dbExpress 控件集的世界之中,让开发人员快速地学习如何使用这些新的控件开发应用系统。1.2 建立第一个 dbExpress 数据库应用程序现在就让我们快速地使用 dbExpress 来开发一个数据库
5、应用程序,学习如何使用 dbExpress 控件来存取数据。要连接数据库并且从其中存取数据,开发人员可以使用以下三个步骤来完成这项工作:1. 使用 TSQLConnection 控件连接数据库;2. 使用 TSQLDataSet 控件存取数据;3. 显示数据在数据感知控件之中。现在就让我们一步一步地来完成上面的三个步骤。步骤 1 使用 TSQLConnection 控件连接数据库首先点击 Delphi 的 File|New|VCL Forms Application-Delphi For Win32 菜单建立一个新的 Delphi 项目,接着点击控件集中的 dbExpress 页签,选择第一个
6、控件 TSQLConnection,并且放入应用程序的主窗体,如图1-2 所示。有了 TSQLConnection 控件之后,现在我们要让它连接到数据库服务器,在这个范例中是使用InterBase,读者也可以使用其他数据库,例如 Oracle 或是 MySQL 等。图 1-2 在主窗体中放入 TSQLConnection 控件以连接数据库要使用 TSQLConnection 连接数据库,请使用鼠标双击 TSQLConnection,此时会出现 TSQLConnection 的控件编辑器,如图 1-3 所示。在图 1-3 中列出了目前 dbExpress 内定的连接或是用户新增的连接,由于现在本
7、范例要使用 InterBase 作为连接的数据库,因此,请使用鼠标点击上方的 【+ 】按钮以建立一个新的连接。图 1-3 TSQLConnection 控件的控件编辑器此时,Delphi 会显示图 1-4 所示的新连接对话框,请在这个对话框中选择使用 InterBase 驱动程序,并且输入一个连接名称。在这个范例中使用了 CHINESEDEMO 作为本范例的连接名称。图 1-4 dbExpress 的新数据库连接对话框接着 Delphi 会显示图 1-5 所示的对话框,要求输入 CHINESEDEMO 真正的数据库路径和名称信息,请如图 1-5 般输入数据库的物理位置。由于 CHINESEDE
8、MO 使用的 InterBase 数据库是使用 GB_2312 编码建立的,因此,请读者记住改变 ServerCharSet 的属性值为 GB_2312。在输入了数据库物理位置之后,读者可以点击对话框上方的【】按钮,以测试是否可以正确连接到数据库。确定一切正确之后,最后点击【OK】按钮以完成设定 TSQLConnection 控件的步骤。1图 1-5 输入 CHINESEDEMO 要连接的 InterBase 数据库读者可以在本书的附属光盘中找到 CHINESEDEMO.GDB 这个 InterBase 数据库。如果读者仔细观察图 1-5 中的对话框,便会发现刚才设定的 CHINESEDEMO
9、 这个 InterBase 连接信息事实上是储存在BorlandBDS4.0dbExpress 目录下的 dbxconnections.ini 文件之中的,这是一个文本文件,读者也可以使用文字编辑器,例如 NotePad 或是 Delphi 的编辑器来修改其中的内容。现在请点击对象查看器,设定TSQLConnection 的 LoginPrompt 属性值为 False,以避免出现登录对话框,最后再把 Connected 属性值设定为 True。这样一来,我们就成功地连接到 InterBase 服务器了(当然,读者的 InterBase 服务器必须在运行中) 。步骤 2 使用 TSQLData
10、Set 控件存取数据现在再从 dbExpress 页签中选择第二个控件 TSQLDataSet,并且放入主窗体中。先在对象查看器中设定它的 SQLConnection 属性值为步骤 1 放入的 SQLConnection1,然后点击它的 CommandText 属性值。此时,Delphi 便会显示 CommandText 属性的属性值编辑器,让开发人员使用可视化的方式下达 SQL 命令。图 1-6 便是启动 CommandText 属性值编辑器的画面。图 1-6 TSQLDataSet 的 CommandText 属性值编辑器当 CommandText 属性值编辑器出现时,它会自动地从连接的数
11、据库中取得所有目前可以被看到的数据表名称,放入到加左上方的 Tables 列表框中,而把选择的数据表的字段信息呈现在左下方的列表框中,真正的 SQL 命令则是在右边的 Memo 控件中。至于什么数据表会出现在左上方的 Tables 列表框中,则是由TSQLConnection 的 TableScope 属性值来决定的。由于 CHINESEDEMO 中只有一个数据表 BIOLIFE,因此,请使用鼠标双击左上方的 BIOLIFE,再双击左下方的*以代表要从 BIOLIFE 数据表中取得所有字段的数据,这样一来,CommandText 属性值编辑器便会在右边的 SQL 窗口中自动产生 select
12、* from BIOLIFE 的 SQL 命令,如图 1-7 所示。图 1-7 使用 CommandText 属性值编辑器完成 SQL 命令请点击【OK】按钮,Delphi 便会把刚才完成的 SQL 命令储存在 TSQLDataSet 控件的 CommandText 属性值中。接着在主窗体中放入一个从 Data Access 控件种类中选择的 TDataSource 控件,设定它的 DataSet 属性值为刚才的 TSQLDataSet 控件,再放入一个 TDBNavigator 控件,设定它的 DataSource 属性值为刚放入的 TDataSource 控件。现在我们就可以借助把 TSQ
13、LDataSet 的 Active 属性值设定为 True,把数据从 BIOLIFE 数据表中取到应用程序中。接着启动 TSQLDataSet 的字段编辑器把代表 BIOLIFE 每一个字段的字段对象加入到应用程序中,这样做的好处是开发人员可以使用 Delphi 的对象查看器来设定字段对象的属性,例如字段显示的中文名称,或是设定字段显示的宽度等。请点击主窗体中的 TSQLDataSet 控件,按下鼠标右键,Delphi 会显示一个快捷菜单, 菜单中的第一个选项Fields Editor便可以启动字段编辑器,如图 1-8 所示。图 1-8 启动 TSQLDataSet 的字段编辑器请点击这个选项
14、,Delphi 便会显示一个空白窗口,然后在这个空白窗口中点击鼠标右键,Delphi 便会显示一个快捷菜单,点击这个菜单中的Add all fields选项,以便把 BIOLIFE 数据表中代表每一个字段的字段对象加入到应用程序中,如图 1-9 所示。接着 Delphi 便会把所有的字段对象加入到刚才的空白窗口中,现在我们就可以点击这个窗口中的每一个字段对象,然后使用对象查看器来设定它们的属性值。图 1-9 加入所有的字段对象当我们在图 1-9 中把字段对象加入之后, Delphi 便会在主窗体中自动声明这些字段对象:TForm30 = class(TForm)SQLConnection1:
15、TSQLConnection;SQLDataSet1: TSQLDataSet;DataSource1: TDataSource;DBNavigator1: TDBNavigator;SQLDataSet1SPECIES_NO: TFloatField;SQLDataSet1CATEGORY: TStringField;SQLDataSet1COMMON_NAME: TStringField;SQLDataSet1SPECIES_NAME: TStringField;SQLDataSet1LENGTH_CM: TFloatField;SQLDataSet1LENGTH_IN: TFloatFi
16、eld;SQLDataSet1TOPOTYPE: TStringField;SQLDataSet1GRAPHIC: TBlobField;我们可以看到 dbExpress 会根据数据表中字段的数据类型而使用 dbExpress 中相对的类声明,例如字段数据类型如果是 char 或是 varchar,就以 TStringField 类型声明,而如果字段数据类型是 BLOB 的类型,就以 TBlobField 类型声明,稍后开发人员就可以直接借助这些变量来存取和操作字段数据。现在我们希望应用程序在执行时是显示中文的字段名称,而不是数据表中字段的英文名称,那么,我们就可以点击图 1-9 中的每一个字
17、段对象,然后在对象查看器中设定字段对象的 DisplayLabel 属性,接着输入这个字段的中文代表名称即可。例如图 1-10 便是设定 SPECIES_NO 这个字段的中文代表名称的画面。图 1-10 使用对象查看器设定字段对象的属性值在我们设定完毕每一个字段对象的 DisplayLabel 属性值之后,便可以选择所有的字段对象,然后把它拖曳到主窗体中,那么 Delphi 便会自动地在主窗体中产生能够适当显示每一个字段对象的数据感知控件,并且显示数据在这些数据感知控件之中。例如图 1-11 便是把图 1-10 中所有字段对象拖曳到主窗体之中后的画面。图 1-11 拖曳所有字段对象到主窗体之中
18、现在我们已经完成了第一个使用 dbExpress 控件实现的范例数据库应用程序,请执行它,此时我们便可以看到类似图 1-12 的画面。dbExpress 控件果然可以顺利地从 InterBase 中存取数据,并且显示在数据感知控件之中,就和 Delphi 原本的 BDE/IDAPI 控件一样方便。图 1-12 范例应用程序执行的画面,请注意 TDBNavigator 中所有和变更数据有关的按钮都被暂停,代表应用程序无法变更数据如果读者仔细观察图 1-12 的画面,便会发现图 1-12 中的 TDBNavigator 中所有和变更数据有关的按钮,例如代表修改数据的【】按钮和新增数据的【+】按钮,
19、都被暂停使用。这意味着我们无法使用这个范例应用程序来变更 BIOLIFE 数据表中的数据,也代表由 dbExpress 控件开发的数据库应用程序在内定上是无法变更的。现在如果读者点击往下一笔的按钮移动到随后的记录,接着再点击往前的按钮欲把目前的记录移动到前一笔时,此时范例应用程序便会显示如图 1-13 所示的错误信息。图 1-13 点击 TDBNavigator 中的前一笔数据的按钮时,范例应用程序会发生错误出现这个错误信息是由于 dbExpress 控件开发的应用程序只能向后走的单向 Cursor,而无法再向前走回到前面的记录。也许读者会觉得奇怪,既然 dbExpress 无法变更数据,也无
20、法任意移动目前记录的位置,那么 dbExpress不是一点用处都没有吗?如何才能用来开发实际的数据库应用程序呢?当然不是,这是因为 dbExpress 使用了和以往 BDE 控件不一样的方式来设计,因此,如果读者是以使用BDE 的概念来使用 dbExpress 便会觉得奇怪。事实上,dbExpress 不但能够做到和 BDE 控件一样的功能,甚至比 BDE 还有更多的功能,在执行效率上也胜过 BDE。在本书进一步介绍如何使用 dbExpress 变更数据之前,先让我们说明 dbExpress 控件的一些重要的概念,以及它的设计架构,这样读者应该会更清楚地了解 dbExpress 的设计原理,在
21、稍后的章节中也能更好地掌握 dbExpress。1.3 使用 dbExpress 的概念dbExpress 控件集中与存取数据有关的控件,例如 TSQLDataSet、TSQLTable 等都是从 TDataSet 类继承下来的,因此,它们提供了所有和 TDataSet 一样的功能,也可以和 Delphi 的数据感知控件使用在一起以开发数据库应用程序。图 1-14 显示了这些 dbExpress 控件的类架构图。图 1-14 dbExpress 的类架构图虽然 TSQLDataSet 等控件是从 TDataSet 继承下来的,但是它们与其他从 TDataSet 继承下来的控件,例如TBDEDa
22、taSet 等控件不同。不同的是借助这些 dbExpress 控件取得的结果数据集是只读的。也就是说,由这些控件存取到的数据是不能够修改的,而且由这些 dbExpress 控件取得的结果数据集,其存取数据的方式只能由前往后存取,而无法由后往前存取。另外值得注意的是,在 Delphi 2006 中 TCustomSQLDataSet已经改为从 TWideDataSet 中继承下来,而不像 Delphi 6/7/2005 是从 TDataSet 继承下来的。这是因为Delphi 2006 的数据集类群组为了准备支持 Unicode,而加入了新的类 TWideDataSet,所有其他 TDataSe
23、t的派生类都改为从 TWideDataSet 继承。TWideDataSet 类在原本的 TDataSet 类服务中加入了同样的服务方法,但是采用了 WideString 的版本,这样一来,数据集类群组就能够处理日后的 Unicode 了。不过由于TWideDataSet 也是从 TDataSet 继承下来的,因此,这样的改变并不会影响原有数据集类群组的执行行为。如果开发人员想要变更由这些 dbExpress 取得的数据,或是想要在结果数据集中以任意的方式移动目前记录的位置,那么开发人员可以使用两种方法来达成:1. 在应用程序中再搭配使用控件集 Data Access 页签中的 TDataSe
24、tProvider 和 TClientDataSet 控件;2. 使用 dbExpress 控件集中的 TSimpleDataSet 控件。稍后本书将会介绍如何使用这两种方式,现在先让我们介绍如何使用同样位于控件集 dbExpress 页签中的TSimpleDataSet 控件。TSimpleDataSet 控件是 Delphi 2006 用来简化开发人员借助 dbExpress 控件变更数据的控件。使用TSimpleDataSet 控件略等于使用 TSQLDataSet 控件与 TDataSetProvider 控件,再加上 TClientDataSet 控件。TSimpleDataSet
25、不但能够存取数据,更能让开发人员变更数据和移动目前记录的位置。基本上,TSimpleDataSet 控件是使用 TSQLDataSet 控件从后端数据源中取得数据,再借助内部的缓存机制(cache)管理数据,借助内部缓冲(buffering)区机制允许开发人员任意地移动目前所记录的位置,并在开发人员需要变更数据回数据源时,根据它内部维持的信息,自动帮助开发人员产生变更数据的 SQL 语句,再借助 TSQLDataSet 控件使用这些自动产生的 SQL 语句把变更数据更新回数据源之中。因此,TSimpleDataSet 控件等于是帮助开发人员撰写了管理数据以及更新变更数据回数据源的程序代码,而无
26、须开发人员自己撰写这些程序代码。图 1-15 就是 TSimpleDataSet 控件的类架构图,从图中可以看到 TSimpleDataSet 是从包含缓存机制的TCustomClientDataSet 控件继承下来的。图 1-15 TSimpleDataSet 的类架构图当开发人员使用 TSimpleDataSet 时,无须再搭配使用 TSQLConnection 和 TSQLDataSet,因为TSimpleDataSet 自己会在内部建立暂时的 TSQLConnection 控件、TDataSetProvider 控件以及一个TInternalSQLDataSet 控件。TSimpleD
27、ataSet 会使用内部建立的 TSQLConnection 连接至数据库,再使用内部建立的 TInternalSQLDataSet 和 TDataSetProvider 处理数据。由于 TSimpleDataSet 内部使用了TDataSetProvider 控件,因此提供了数据变更的能力,这样比使用前面的 TSQLDataSet 只提供数据查询的能力方便多了。此外,虽然开发人员在 Delphi 2006 中是使用 dbExpress 控件存取和处理数据的,但在 dbExpress 控件之下,开发人员仍然必须拥有每一个特定数据库的 dbExpress 驱动程序才可以存取特定的数据库。当开发人
28、员像图 1-5 那样使用 TSQLConnection 控件指定连接特定的数据库时,dbExpress 便会加载与此数据库相关的dbExpress 驱动程序以存取这个数据库。如果 dbExpress 想存取到特定的数据库,那么加载的 dbExpress 驱动程序仍然需要调用特定数据库的客户端驱动程序,才能够真正地存取特定数据库。例如要使用 dbExpress 存取 Oracle,那么除了要在 dbExpress中存取 Oracle 的 DBXORA30.DLL 这个驱动程序之外,由于 DBXORA30.DLL 是直接调用 Oracle 的 Oracle Call Interface (OCI)
29、 ,因此,还需要 Oracle 客户端的 OCI.DLL,否则 dbExpress 无法存取 Oracle 数据库。例如图 1-16 就是 dbExpress 在存取数据库时实际的架构。当 dbExpress 控件要存取 Oracle 时,就使用了刚才叙述的流程。例如 dbExpress 要存取 InterBase 时,就需要加载 dbExpress 中存取 InterBase 的DBXINT30.DLL 驱动程序,以及 InterBase 客户端的引擎 GDS32.DLL。图 1-16 dbExpress 存取各种不同关系数据库的架构图前面已经介绍过,在 dbExpress 控件借助驱动程序
30、取得了结果数据集之后,开发人员可以再使用TSimpleDataSet 来变更结果数据集之中的数据,因为 TSimpleDataSet 包含了内部缓存的机制,可以自动帮助开发人员完成这些工作。如果我们再详细地介绍什么是 TSimpleDataSet 内部缓存的机制,那么答案就更清楚了,这个缓存的机制事实上就是以前 Delphi 版本中的 MIDAS 技术。Delphi 2006 中的 MIDAS 已经是第 7 个版本了(Delphi 7 中的 MIDAS 是第 5 个版本) ,从 Delphi 6 开始它重新被命名为 DataSnap 技术。Delphi 2006 中的 DataSnap 已从以
31、往定义为分布式应用系统架构技术转换为跨平台的标准数据存取技术。这个意思是说,MIDAS 7 不但可以使用开发分布式应用系统,在 Delphi 2006 也成为开发客户/服务器以及单机应用程序的标准存取数据的技术,并且能够同时使用在 Windows 平台的 Delphi 2006 中以及.NET 1.1平台之中。因此,DataSnap 已经成为 Delphi 的核心技术之一,所有的 Delphi 开发人员都必须了解并且熟练地掌握 DataSnap 的技术,当然,本书也会充分地说明如何善用 DataSnap 技术。因此,在 Delphi 2006 中开发数据库应用程序的架构就如图 1-17 所示的
32、一样,应用程序借助 dbExpress 存取到数据,再由 DataSnap(MIDAS 7)来管理和变更数据。图 1-17 dbExpress 应用程序执行架构图图 1-18 是更详细的架构图, Delphi 2006 中的应用程序借助 dbExpress 控件存取数据,而 dbExpress 是使用SQL 语句从数据源中取得数据,当数据源根据 SQL 语句执行的结果数据集并且回传给 dbExpress 控件之后,dbExpress 控件会再把结果数据集交由 DataSnap 技术来管理,以便开发人员能够对结果数据集中的数据进行处理和变更。从图 1-18 中我们也可以了解到,借助 TSimpl
33、eDataSet 取得的数据事实上就是由 DataSnap 在缓存内存中维护的数据。几乎所有借助 TSimpleDataSet 的方法或是属性值处理的数据都是储存在这些缓存内存中的数据,只有当开发人员真正需要把缓存内存中的数据更新回数据源时,DataSnap 才会借助 SQL 语句把经过变更的数据更新回数据库中,在稍后的章节中会说明如何变更数据并且把数据真正地更新回数据源中。图 1-18 dbExpress 应用程序执行详细架构图1.4 使用 dbExpress 变更数据现在我们已经介绍了 dbExpress 的架构和原理,接下来将详细介绍 dbExpress 技术的精髓,让开发人员能够精确地
34、掌握 dbExpress 技术。不过在学习 dbExpress 的其他功能之前,先让我们以实际的范例来说明是如何使用 dbExpress 任意移动记录位置和变更数据的。本节也将同时介绍如何使用 TSimpleDataSet,以及使用 TSQLDataSet 搭配 TDataSetProvider 和TClientDataSet 控件,以便证明在前面章节中提到的变更数据的方式。首先让我们延续前面 1.2 节的范例来说明如何完整地处理 CHINESEDEMO 中 BIOLIFE 数据表的数据。第 1 步是让 1.2 节中使用的范例程序搭配 TDataSetProvider 和 TClientDat
35、aSet 控件。1.4.1 使用 TSQLDataSet 搭配 TDataSetProvider 和 TClientDataSet 控件请回到 Delphi 2006 集成开发环境,打开前面的范例应用程序的主窗体,然后在主窗体中加入控件集 Data Access 页签中的 TDataSetProvider 和 TClientDataSet 控件,此时范例主窗体的画面如图 1-19 所示。在前一节中已经说明了由 dbExpress 取得的结果数据集虽然无法修改,但是只要搭配 Delphi 的 DataSnap技术就能够允许应用程序变更其中的数据。因此,现在我们要做的就是在范例应用程序中加入 Da
36、taSnap的功能。图 1-19 在范例主窗体中加入 TDataSetProvider 以及 TClientDataSet 控件在加入了 TDataSetProvider 控件之后,使用对象查看器设定它的 DataSet 属性值为主窗体中原先的TSQLDataSet 控件,如图 1-20 所示。图 1-20 设定 TDataSetProvider 控件的 DataSet 属性值TDataSetProvider 控件能够把属于 TDataSet 类的控件,例如 TSQLDataSet(请参考图 1-14 的类架构图) ,输出给 TClientDataSet 控件,以便让 TClientDataS
37、et 控件能够管理输出 TDataSet 控件之中的结果数据集数据。接着使用对象查看器设定刚才加入的 TClientDataSet 控件的 ProviderName 属性值为主窗体中的TDataSetProvider 控件,如图 1-21 所示。图 1-21 设定 TClientDataSet 控件的 ProviderName 属性值现在 TClientDataSet 控件便可以管理由 TDataSetProvider 输出的数据,而 TDataSetProvider 输出的数据就是它连接的 TSQLDataSet 从后端数据源中取得的结果数据集。最后把主窗体中的 TDataSource 控件
38、的 DataSet 属性值从原先的 TSQLDataSet 改为刚才加入的TClientDataSet 控件,再把 TClientDataSet 控件的 Active 属性值设定为 True,这样一来,TClientDataSet 便从 TDataSetProvider 取得数据,并且显示在主窗体的数据感知控件之中。现在执行这个范例应用程序,读者就会看到类似图 1-22 所示的画面,从图中我们可以看到在使用了TDataSetProvider 和 TClientDataSet 之后,范例应用程序便可以使用 TDBNavigator 任意地移动目前的记录,也不会出现错误了。因此,使用 DataSn
39、ap 技术之后,dbExpress 单向 Cursor 的限制就已经被克服了。此外,TDBNavigator 中的新增、修改和删除按钮似乎也可以工作,而不像图 1-12 中一样被暂停使用。读者可以先在范例应用程序中试着修改或删除数据,然后点击【】按钮把数据更新回去。这样做似乎是正确的,但是如果读者结束范例应用程序,然后再次执行范例应用程序,会发现原先修改或删除的数据又出现在范例应用程序中,这代表刚才修改和删除的操作并没有真正对数据发生作用,这是为什么呢?图 1-22 执行修改过的范例程序这是因为在使用 DataSnap 的应用程序中,当应用程序变更数据并且调用 TClientDataSet 的
40、 Post 方法或是点击 TDBNavigator【】按钮更新数据时,只是把数据更新回图 1-18 中由 DataSnap 管理的缓存内存中,而数据并没有真正更新回后端数据源之中。要真正把变更的数据更新回数据源中,开发人员必须再调用TClientDataSet 的 ApplyUpdates 方法。TClientDataSet 的 ApplyUpdates 方法会把图 1-18 中由 DataSnap 管理的缓存内存中所有已经被变更的数据,包含新增、修改和删除的数据,一起更新回后端数据源中。TClientDataSet 事实上是借助它连接的TDataSetProvider 控件自动产生 SQL
41、语句帮助开发人员更新数据的,在稍后的章节中会详细介绍这个流程。下面是 ApplyUpdates 方法的声明原型:function ApplyUpdates(MaxErrors: Integer); Integer; virtual;ApplyUpdates 方法接受一个整数类型的参数:MaxErrors。MaxErrors 代表当 TDataSetProvider 自动更新数据时,开发人员所允许发生的错误次数。我们已经说明了当调用 ApplyUpdates 方法时,DataSnap 会将所有在缓存内存中自上次调用 ApplyUpdates 方法之后到本次调用 ApplyUpdates 方法之间
42、所有已变更的数据,一起进行更新。因此,这可能会有许多的变更数据,而 MaxErrors 就代表在更新这些数据时开发人员允许更新数据时发生错误的次数。如果 ApplyUpdates 在更新数据时发生了超过 MaxErrors 指定笔数的次数,那么这整个更新的操作便会被恢复。相反,如果发生的次数小于或等于 MaxErrors,那么成功更新的数据仍然会被更新回数据源中,至于没有成功更新的数据,则可以让开发人员借助错误事件处理函数来决定如何处理这些失败的数据,我们将在异常处理的章节中详细介绍。如果传入给 ApplyUpdates 方法的 MaxErrors参数是 0,代表不允许发生任何的更新错误;如果
43、传入的参数为1,代表不管发生多少错误都没有关系,可以先把能够成功更新的数据更新回数据源之中。因此,现在要把范例应用程序变更的数据更新回数据源之中便非常简单了,只需要在范例应用程序中调用TClientDataSet 的 ApplyUpdates 方法即可。现在请在主窗体中加入一个 TButton,设定它的 Caption 属性值为 ApplyUpdate,如图 1-23 所示。图 1-23 在范例主窗体中加入 TButton 控件接着在 TButton 的 OnClick 事件处理函数中撰写如下的程序代码:procedure TForm1.Button1Click(Sender: TObject
44、);beginClientDataSet1.ApplyUpdates(0);end;上面的程序代码调用了 TClientDataSet 的 ApplyUpdates 方法,并且传入的参数为 0,这代表不允许发生任何的错误。如果在变更数据时发生了任何问题,那么 DataSnap 便会产生异常,让开发人员得以处理错误状况,在稍后的章节中我们会介绍如何处理 DataSnap 的异常状况。请再次执行范例应用程序,试着修改数据,然后点击主窗体中的【ApplyUpdate 】按钮,读者便会发现现在的数据真的被更新回后端数据源中了,如图 1-24 所示。图 1-24 范例程序现在可变更数据了当然,如果读者不
45、希望用户另外点击按钮就能够把数据更新回数据源中,那么读者可以在 TClientDataSet的 AfterPost 事件处理函数中直接调用 TClientDataSet 的 ApplyUpdates 方法,如下所示:procedure TForm1.ClientDataSet1AfterPost(DataSet: TDataSet);beginClientDataSet1.ApplyUpdates(0);end;不过,这样写应用程序会降低一些执行效率,因此,读者可以让 TClientDataSet 的变更数据在一定的笔数之后再调用 ApplyUpdates 方法,一次更新所有的数据。这样做比较
46、有效率,我们在稍后的章节中会介绍如何达到这种效果。从这个范例中读者可以知道,使用 dbExpress 和 DataSnap 的应用程序似乎比较麻烦,然而事实上并非如此,因为在下一节讨论 TSimpleDataSet 时读者便会知道我们可以借助 TSimpleDataSet 简化这些工作。使用 dbExpress 和 DataSnap 比传统的开发方式有许多的优点,例如这样做比传统使用 BDE 的应用程序有更好的执行效率,也可以轻易把应用程序改为分布式的 N-Tier 应用系统,还可以把应用程序移植到Linux/.NET 上。这些好处都是传统的开发方式无法轻易达成的,在读者熟悉了 dbExpre
47、ss 和 DataSnap 之后,可能就不再想使用传统的数据库开发方式了。1.4.2 使用 TSimpleDataSet 控件在前一节中讨论了使用 TSQLDataSet 加上 TDataSetProvider 和 TClientDataSet 控件开发应用程序的方式。由于在使用 dbExpress 开发数据库应用程序时一定需要使用这些控件的组合,因此, Delphi 2006 的DataSnap 控件集便提供了一个新的控件 TSimpleDataSet 来帮助开发人员简化使用 dbExpress 开发数据库应用程序的步骤。简单地说,TSimpleDataSet 控件就等于 TSQLDataS
48、et 加 TDataSetProvider 和 TClientDataSet 控件,因此,开发人员只须使用一个 TSimpleDataSet 控件便可以开发变更数据的应用程序。下面来介绍如何使用TSimpleDataSet 控件。首先点击 Delphi 的 File|New|VCL Forms Application-Delphi For Win32 菜单建立一个新的 Delphi 应用程序,然后如同 1.2 节说明的方式连接 InterBase 数据库。在主窗体中放入位于 dbExpress 页签的 TSimpleDataSet控件,请读者注意图 1-25 显示了 TSimpleDataSe
49、t 已经在内部自动建立了 TSQLConnection 和 TDataSet 控件,并且命名为 InternalConnection 和 InternalDataSet,此时开发人员就可以直接使用 TSimpleDataSet 的InternalConnection 和 InternalDataSet 控件连接和处理数据,而无须再额外使用 TSQLConnection 和TSQLDataSet 了。图 1-25 TSimpleDataSet 控件会自动在内部建立 TSQLConnection 和 DataSet 控件现在我们可以直接在对象查看器中展开 TSimpleDataSet 的 InternalConnection 和 InternalDataSet 的属性值并且设定连接到 CHINESEDEMO 数据库,再设定 TSimpleDataSet 的 DataSetCommandText 属性值从BIOLIFE 数据表中取得数据,如图 1-26 所示,最后再设定 TSimpleDataSet 的 Active 属性值为 true,以便从数据源中取得数据。图 1-26 使用对象查看器直接设定 TSimpleDataSet 的 InternalConnection 和 InternalDataSet 的属性值接着在主窗体中放入 TDat