2.48k likes | 2.73k Views
第 12 章 应用开发实例. 本章学习目标 l 理解 ADO 对象结构和编程模型,并正确为项目添加 ADO l 通过在 Delphi 中使用数据库对象加深对 SQL Server 数据库的理解 l 完成基于 SQL Server 的数据库系统实例开发. 12.1 ActiveX 数据对象 ——ADO. 12.1.1 ADO 对象结构 1 . ADO 简介
E N D
本章学习目标 • l理解ADO对象结构和编程模型,并正确为项目添加ADO • l通过在Delphi中使用数据库对象加深对SQL Server 数据库的理解 l完成基于SQL Server的数据库系统实例开发
12.1 ActiveX数据对象——ADO 12.1.1 ADO对象结构 1.ADO简介 ADO(Active Data Objects)是微软公司推出的一个功能强大的数据库应用编程接口,它的主要功能是用于应用程序与OLE DB兼容的数据源的连接。应用程序可以通过ADO实现对各种类型数据库的连接,对数据的查询、修改、更新等,因而,通过ADO存取数据已经成为最佳选择。 介绍ADO,不能不提到UDA。Universal Data Access (UDA)是微软公司推出的对数据库操作的一个策略,它通过易用的API接口能在一个程序中从多种数据源中轻易的访问数据。UDA通过Microsoft Data Access Components(MDAC)来实现,而MDAC则包括ADO、Open Database Connectivity(ODBC)与OLE DB。其中,OLE DB被微软公司归类为系统级的接口,定义了一套COM接口,提供从关联数据库及文件系统访问数据的能力,设计用来给系统级的程序员使用。它虽然灵活、功能强大,但仍属于较低级的接口,并且对程序员的要求较高,需要较高水平的知识。ADO是在OLE DB之上的一个层面,被用来沟通这个低级接口与数据库,简化并实现OLE DB的强大功能,它是为应用程序员设计的。ODBC为了向后兼容也包含在MDAC中,但ODBC有被OLE DB替代的趋势。OLE DB可直接用于Microsoft Access、Microsoft SQL以及Oracle等。ODBC、OLE DB、ADO在访问数据存储体时的层次关系如图12-1所示。
2.ADO对象结构 图12-2给出了ADO对象总体结构。如图中所见,ADO存在五个主要的对象: • lConnection 程序和数据存储之间的连接。 • lCommand 允许运行相对于数据存储的命令。 • lRecordser 包含从数据存储的特定操作中返回的所有数据。 • lRecord 允许处理半结构(semi-structured)存储中存储的数据(如在某个目录结构中的文件),就像这些数据记录在数据库中一样。 • lStream 允许处理Web资源中的数据,如HTML文件。 ADO的五个主要对象处在同一层次上,也就是说,可以在程序中建立任何一个所需要的对象,而无需建立父级对象。例如,可以使用Recordset对象产生数据存储的直接请求,此时不需要首先建立显式的Connection对象,ADO将自动进行这些必要的工作。
还有四个子对象——Property、Parameter、Field和Error(以及它们的相关集合Propertys, Parameters, Fields和Errors),图12-2中只给出了三个集合,Properties集合被有意隐去,这样可以很容易地看到主对象相互之间的作用关系。Properties集合与其他对象之间的关系如图12-3所示。 图12-2 ADO对象结构
Delphi将ADO的一些常用对象,封装为TADOConnection, TADOCommand, TADODataSet。另外,为了与Delphi接口的统一,Delphi亦建立了几个类似BDE组件的TADOTable, TADOQuery, TADOStoredProc,这些都放在ADO选项卡中。为了方便读者掌握和理解后面用Delphi开发的综合实例,我们先对Delphi中的ADO组件作简要介绍。
12.1.2 TADOConnection组件 TADOConnection组件封装ADO的Connection对象,它专用于数据库的连接,且可以提供作为多个TADODataSet, TADOCommand共享的数据来源。虽然ADOConnection并非必要,因为ADOCommand, ADODataSet都可以通过ConnectionString属性直接连接到数据存储体,但是,通过单一ADOConnection连接有两个最大的优点,就是它能减少资源的浪费,同时,它允许我们建立跨多个DataSet的事务。
1.TADOConnection组件常用的属性 • lCommandCount 通过ADOConnection连接已打开的ADOCommand对象。 • lCommands 通过ADOConnection连接已打开的ADOCommand对象数组。 • lConnected Connected属性用来设置连接,也用来检查目前是否处于连接打开的状 态。 • lConnectionString 设置ADO连接字符串参数,其参数定义如下所示: • uProvider 数据提供者的名称。 • uFile name 包含连接信息的文件名称。 • uRemote Provider 提供客户端连接的远程数据提供者名称。 uRemote Server 提供客户端连接的服务器路径名称。
这些参数虽然看似复杂,但我们可以利用它的向导帮助,很轻松地设置这个参数字符串,步骤如下:这些参数虽然看似复杂,但我们可以利用它的向导帮助,很轻松地设置这个参数字符串,步骤如下: ①进入Delphi集成开发环境,单击【ADO】选项卡,如图12-4,向Form中添加一个【ADOConnection】对象,选中该对象,如图12-5。 图12-4 【ADO】选项卡
②在如图12-6所示的【Object Inspector】属性设置窗口中,选择【ConnectionString】辅助按钮或由组件的快捷菜单【Edit Connection String】进入设置对话框,如图12-7。 图12-6 【属性设置】窗口图12-7 【ConnectionString】设置对 话框
③选择【Build...】按钮,打开【数据链接属性】对话框,如图12-8所示。③选择【Build...】按钮,打开【数据链接属性】对话框,如图12-8所示。 图12-8 【数据链接属性】对话框
④单击【下一步】按钮,设置【连接】选项卡,选择服务器名称、用户名称、密码、数据库名称等,如图12-9;可以单击【测试连接】按钮,测试是否连接成功,单击【确定】按钮完成设置,如图12-10所示④单击【下一步】按钮,设置【连接】选项卡,选择服务器名称、用户名称、密码、数据库名称等,如图12-9;可以单击【测试连接】按钮,测试是否连接成功,单击【确定】按钮完成设置,如图12-10所示 图12-9 设置【连接】选项卡
lConnectionTimeout 设置尝试连接的时间秒数,默认15秒。超过指定时间时,若尚未连接成功或取消连接,则中断连接要求,并触发异常(Exception)。 • lConnectOptions 连接选项,用来设置同步或异步连接,默认同步。通常,除非连接的服务器很慢,否则,不需要设置为异步连接。 • lCursorLocation 指定采用客户端或服务器端记录指针,默认采用客户端指针(clUseClient)。虽然采用服务器端指针比较缺乏灵活性,但有时候为了防止空间不足,或者配合特定数据库系统的访问方式,会采用服务器记录指针。 • lDataSetCount 通过ADOConnection连接、已打开的DataSetCount对象。 lDataSets 通过ADOConnection链接、己打开的DataSets对象数组。
lErrors Errors实现ADO模型的错误集合,但很少(也不建议)直接使用,请参考Microsoft Data Store SDK说明。 • lProperties Properties属性记录ADO模型对应的Properties集合对象,请参考Microsoft Data Store SDK说明。 • lProvider 指定ADO连接的数据提供者(见图12-6)。 • lState 取得目前ADOConnection的连接状态,可能的状态如下所示: • uStClosed ADOConnection未连接,无法使用。 • uStOpen 己连接(但不一定成功)。 • uStConnecting 正在尝试连接中。 • uStExecuting 正在执行指令。 • uStFetching 正在提取数据。 lVersion 取得ADO目前使用版本。
2.TADOConnection组件常用的方法 • lBeginTrans 开始一个新的事务,其对象为ADOConnection连接的数据保存体。调用BeginTrans成功后,触发OnBeginTransComplete事件,并将属性InTransaction设为True。 • lCancel Cancel仅用于异步的数据连接,并且,该连接必须在调用Open后,但尚未连接成功前。 lCommitTrans 用来确认事务的执行,将该事务开始直到调用CommitTrans期间所有对数据库的操作改变,写回数据库。成功时触发OnCommitTransComplete事件,并结束事务(InTransaction属性设为False)。
lExecute 执行CommandText属性的SQL命令字符串,其参数中,ExecuteOptions用来设置Execute的选项,可能值如下所示: • uEoAsyncExecute 以异步执行。 • uEoAsyncFetch 以异步提取数据。 • uEoAsyncFetchNonBlocking 无阻碍地以异步方式提取数据。 • uEoExecuteNoRecords 不返回记录。 • lGetFieldNames 取得数据库中指定数据表的所有字段。 • lGetTableNames 取得数据库中,所有的数据表名称,默认只取得非系统数据表。 lRollbackTrans 用来取消事务的所有变动,并结束该事务。调用RollbackTrans成功后,触发OnRollbackTransComplete事件,并且将InTransaction设为True。
3.TADOConnection组件常用的事件 • lOnBeginTransComplete 当BeginTrans成功后,会触发这个事件,参数中,TransactionLevel表示成功的这个事务的事务层数。 • lOnCommitTransComplete 当CommitTrans成功后,会触发这个事件。 • lOnConnectComplete 连接到数据保存体成功时,触发这个事件,这个事件通常通过 Connected设为True或调用Open方法触发。 • lOnDisconnect Connected设为False或调用Close方法触发这个事件。 lOnExecuteComplete 当成功调用Execute方法时,会触发此事件,参数中,Connection表示执行此命令的Connection对象,RecordsAffected则取得成功执行此命令受影响的记录条数。
lOnWillConnect 当Connected设为True或调用Open方法尝试连接时,触发这个事件。 lOnWillExecute当调用Execute在真正执行前,会触发此事件。 12.1.3 TADOCommand组件 TADOCommand组件用来处理无返回DataSet的SQL指令,它对应到ADO模型的Command对象,通过Execute方法执行CommandText属性中的SQL指令(若包含参数,则由Parameters属性设置)。
1.TADOCommand组件常用的属性 • lCommandObject 用来直接访问ADO对象模型的Command对象,这对不直接由TADOCommand组件提供的属性、方法,是非常有用的。直接访问Command对象必须对ADO有较深入的了解,请读者参考"Microsoft Data Store SDK"文件说明。 • lCommandText 设置或取得TADOCommand执行的SQL指令字符串。 • lCommandType 设置或取得指令类型,也就是告诉TADOCommand该如何看待 CommandText字符串。其可能值如下: • uCmdUnknown 未知类型(不指定),此为默认值,但指定明确类型效率会较好。 • uCmdText 将CommandText字符串视为SQL指令(包含对预存程序的调用)。 • ucmdTable CommandText字符串仅包含数据表名称。 ucmdStoredProc CommandText字符串仅包含数据库预存程序(Stored Procedure) 的名称。
lConnection 指定通过哪个ADOConnection组件连接,不指定连接组件时,则直接指定ConnectionString连接字符串。 • lParameters 设置或取得ADOCommand的参数名称、参数值及数据类型,这个属性仅适用于CommandType为cmdText或cmdStoredProc的SQL叙述。 lStates 取得目前ADOCommand的状态,其可能值为:stClosed, stOpen, stConnecting, stExecuting、stFetching。
2.TADOCommand组件常用的方法 • lAssign Assign方法复制参数中的另一个ADOCommand组件,复制的内容包括: Connection(若不存在,则复制ConnectionString)、CommandText, CommandTimeout, CommandType、Prepared及Parameters。 • lCancel Cancel用来中断尚在CommandTimeout时间内的“异步”执行,若对象是同步执行操作,会触发异常。如同前述,要指定异步执行,只要设置ExecuteOptions为eoAsyncExecute即可。 lExecute 执行CommandText指令,若返回Recordset,则可以通过ADODataSet接收,如“ADOQuery1.Recordset:=ADOCommand1.Execute:”或“ADODataSet1.Recordset:=ADOCommandl.Execute;”。
12.1.4 TADODataSet组件 TADODataSet组件用来从单一或多个窗体中获取数据或操作数据存储体的数据,它除了允许通过TADOConnection连接,也可以直接连接到数据服务器。 ADODataSet与ADOCommand相同,都可以用来取得返回的Recordset,最大的不同在于,ADOCommand必须借助其他ADODataSet组件保存返回的Recordset,但却可以处理非返回Recordset的一些操作查询,而ADODataSet则仅能用来取得、存放这些数据记录。 1.TADODataSet组件常用的属性 l RDSConnection RDSConnection属性用来指定ADODataSet的RDS数据连接来源。RDS数据连接用在以ADO为基础的商业逻辑对象(多层架构的服务端应用程序),此处不予探讨。这个属性与Connection属性是互斥的。
lCacheSize CacheSize用来设置一次由服务器端读到客户端内存的数据记录数。当记录指针移动超出指定的记录数范围时,会再读下一批记录。 • lCursorType 记录指针的类型,其可能值如下所示: • uCtUnspecified 不指定。 • uCtOpenForwardOnly 记录指针只能向前移动,无法往回移动,如此,会有较好 的效率。 • uCtKeyset 看不到别人添加的记录,并且,无法访问己被删除的记录,此为默认值。 • uCtDynamic 看得见其他人添加、修改、删除的记录变动,同时可以向前、向后移动记录。 • uCtStatic 静态指针,将原始记录全部复制一份,原始记录的所有变化,都看不 见,静态指针常用于报表。 CursorType必须配合前述的CursorLocation(客户端或服务器端的记录指针)。当设置为客户端光标 (clUseClient ) 时,则CursorType只能是ctStatic。此外,若数据提供者不支持指定的光标类型,会以其他最接近、可用的光标类型代替,但这个替代的光标类型,仍会反映到CursorType属性。
l时,同LockType LockType属性用来设置或取得DataSet打开时,记录如何锁定,其可能值如下所示: • u1tUnspecified 不指定锁定类型。 • u1tReadOnly 目前打开的DataSet是只读的,无法修改数据。 • u1tPessimistic 悲观锁定。悲观锁定在修改模式时,记录以一条一条为基础,以 确保同一个记录不会同时被多人改变。 • u1tOptimistic 优化锁定。优化锁定较适用于多人使用的系统,它只有在真正更 新到数据库时,才会锁定记录。例如,若同时两人更新某条记录,无论谁先更新都可以成功。 • u1tBatchOptimistic 批量优化锁定。批量优化锁定类似优化锁定,但是,它允许整批更新。 与CursorType相同,不同数据库系统支持的LockType也不尽相同,当指定该数据提供者不支持的LockType样会自动转换为最接近、支持的锁定类型。
lMaxRecords 指定ADODataSet选取的最大数据条数,默认为0,表示不限制条数。但是,并非所有数据库都支持这个属性,例如,使用Access测试便无结果。 • lRecNo 目前记录所在的位置。 • lRecordCount 记录条数。TADODataSet继承自TCustomADODataSet尚有另一类似的属性RecordSize,但该属性并未实现,会取得错误值。 • lRecordset Recordset属性提供直接访问ADO的Recordset对象。 • lSort 排序字段,多个字段排序时,以逗号隔开,如“'ORDERDATE ASC,ORDERNO DESC'”依订单日期顺向排序,相同日期时,则再根据订单编号反向排序。需注意的一点,ASC, DESC必须是大写的,省略时,默认顺向排序,取消排序则只要将Sort字符串清除。此外,排序的行为与数据库记录指针的设置值、数据库系统皆有关。 lIsUnidirectional 用来判断DataSet是否仅支持单向操作。
2. TADODataSet组件常用的方法 • lCancelBatch 取消所有由批次更新模式打开,且等待更新的DataSet。其传入参数 AffectRecords可能值如下: • uArCurrent 仅影响目前记录。 • uarf filtered 更新符合Filter条件设置的所有记录。 • uarAll 更新全部记录。 • uarAllChapters 更新全部Chapter记录,对阶层式Recordset而言,即目前等级的全部记录。 要使用批次更新,CursorType必须是默认的ctKeySet或ctStatic,且LockType必须指定为ItBatchOptimistic。
lDeleteRecords 删除一条或多条记录,其参数同CancelBatch的参数AffectRecords当指定的DataSet不能允许删除操作时,会触发异常。 • lSupports 用来检测指定的操作是否被支持,可查询的功能包括: • uCoHoldRecords 未更新变更,仍能撷取更多的记录。 • uCoMovePrevious 是否允许记录往回移动。 • uCoAddNew 是否允许新增记录。 • uCoDelete 是否允许删除记录。 • uCoUpdate 是否允许修改记录。 • uCoBookmark 是否允许定位到指定记录位置。 • uCoApproxPosition 是否支持RecNo属性。 • uCoUpdateBatch 是否支持批量更新。 • uCoResync 是否支持Resync方法更新。 • uCoNotify 是否支持自动通知并返回事件。 • uCoFind 是否支持Locate方法。 • uCoSeek 是否支持Seek方法。 • uCoIndex 是否允许使用IndexName属性指定索引。
使用Supports的方式很简单,如以下程序代码片段,用来检查是否允许往回移动记录指针:使用Supports的方式很简单,如以下程序代码片段,用来检查是否允许往回移动记录指针: If ADOdataSet1.Supports([coMovePervious]) then ShowMessage(‘允许往回移动’); l UpdateBatch 执行批次更新到数据存储体。
3.TADODataSet组件常用的事件 • lOnEndOfRecordset 当Recordset的记录指针移到最后一条时,触发此事件,这个事件通常是内部自行触发,或者通过直接操作ADO的Recordset组件的方法来触发。 • lOnFetchComplete 当异步提取数据时,在数据提取完成后,会触发此事件。 • lOnFetchProgress 异步数据提取的期间,会触发此事件。 • lOnFieldChangeComplete 当Recordset的Field变更时,会触发此事件。 • lOnMoveComplete 当Recordset记录移动时,会触发此事件,需注意的一点,Recordset记录移动与ADODataSet的记录移动是无关的。 lOnRecordChangeComplete 当Recordset一条或多条记录变更完成时,触发此事件。OnRecordChangeComplete事件触发同样与ADODataSet数据变更的事件无关。
lOnRecordsetCreate 当Recordset属性第一次被初始化时,触发此事件。 • lOnWillChangeField 当Recordset的Field正要被改变前,触发此事件,此事件的触发同样与ADODataSet数据变更的事件无关。 • lOnWillChangeRecord 当Recordset的记录变更前,触发此事件,此事件的触发,同样与ADODataSet数据变更无关。 • lOnWillChangeRecordset 当Recordset对象变更前,触发此事件,此事件的触发同样与ADODataSet数据变更的事件无关。 • lOnWillMove 当Recordset记录指针移动前,会触发此事件,此事件的触发同样与 ADODataSet组件的BeforeScroll, AfterScroll等事件无关。
12.1.5 TADOTable组件 TADOTable组件用来操作使用ADO的数据存储体单一数据表,它同样允许直接连接数据存储体,而不通过TADOConnection。 1. TADOTable组件常用的属性 • lMasterSource, MasterFields 通过这两个属性,同样设置Master/Detail的DataSource的关联字段。 • lTableDirect 默认为False,表示ADOTable必须通过SELECT取得字段对应数据,设为True时,ADOTable允许直接通过Table名称取得数据库的字段数据。需注意的一点,并非所有数据提供者都支持直接由数据表名称取得来源的字段数据。 lTableName 设置ADOTable操作的数据表名称,改变此值前,必须先关闭ADOTable (调用Close方法或将Active设为False)。
2.TADOTable组件常用的方法 • lGetIndexNames 取得该数据表可用的索引名称,类似TADOConnection提到的 GetFieldNames, GetTableNames。 12.1.6 TADOQuery组件 TADOQuery组件通过SQL命令操作数据存储体的单一或多个数据表,它同样允许直接连接数据存储体,而不通过TADOConnection。事实上,与TADOTable相同,TADOQuery亦不存在于ADO对象模型,它同样是为了让ADO选项卡中的组件接口与BDE组件相同,方便Delphi程序设计器使用而产生。它常用的属性、方法如下:
1. TADOQuery组件常用的属性 • lDataSource 用来自动填满与参数相同名称的字段对应值,它可以被用于Master/Detail的连接设置。 • lRowsAffected ADOQuery:最后一次更新或删除数据的条数,当其值为-1时,通常 会伴随着触发异常。 • lSQL TADOQuery执行的SQL字符串。 2. TADOQuery组件常用的方法 • lClose 关闭数据集。 • lCreate 创建TADOQuery组件的实例。 lExecSQL 调用ExecSQL执行SQL查询操作。SELECT命令直接用Open方法,而不使用ExecSQL方法,只有在执行没有返回结果集的SQL字符串时使用ExecSQL。
3. TADOQuery组件常用的事件 TADOQuery组件的事件及其说明与TADODataSet组件的事件说明相同。 12.1.7 ADO程序框架 要用ADO组件创建数据库应用程序,应该了解ADO程序的框架。由于Delphi很好地封装了ADO对象,提供了连接组件和数据集组件,因此,建立数据库连接就像开发基于BDE数据库引擎的应用程序那样,使用数据源组件和数据感应组件就可以实现对数据库的各种操作。ADO程序的框架如图12-11所示。从图中可以看出,如果要在一个DBRrid控件中显示数据库中的数据,方法之一是:创建一个DataSource组件,一个ADOQuery组件,一个ADOConnection组件。如果不显式地创建ADOConnection组件,则必须设置ADOQuery组件的ConnectionString属性以连接到数据库。
图12-11 ADO程序的框架 至于如何在Delphi中用ADO组件创建数据库应用程序,如何使用SQL Server数据库表、数据库视图以及如何使用SQL语句对数据库进行操作等,请阅读下一节。
12.2 基于SQL Server的数据库系统开发实例 本节以一个“学生成绩管理系统”为综合实例,既介绍了Delphi数据库应用程序的开发过程,又可从中理解和掌握利用ADO对象对SQL Server 2000数据库进行操作的方法。 12.2.1 系统设计 如同其他管理信息系统一样,“学生成绩管理系统”不仅要对学生的成绩进行管理,还要对与学生成绩有关的其他信息进行管理,如学生的基本信息、系部信息、班级信息、课程信息等管理模块,对每类信息的管理一般都应具有增加、删除、修改和查询功能,有些信息还要对其进行统计和分析。 1. 系统功能描述 本系统的每个管理模块所应完成的任务此处省略。 2. 系统功能划分 本系统的功能如图12-12所示。
3. 系统流程 一般来说,对于一个实用的计算机管理信息系统,都具有对不同的用户赋予不同的操作权限功能,因此不同的用户的操作流程是不一样的。本系统也提供了简单的用户管理功能,如果用户名是“admin”,则表示超级用户。超级用户除可以修改自身的口令外,还可以增加和删除其他用户;普通用户登录后只能修改自己的口令。本系统的流程如图12-13所示。 图12-13 “学生成绩管理系统”系统流程
12.2.2 数据库设计 数据库设计主要包括创建数据库和数据库逻辑结构设计。在设计数据库时通常要进行规范化分析,是各个数据库表满足某种范式的要求,要注意的是并不是将表分割得越细越好,过细不利于提高数据库的存取效率。 在“学生成绩管理系统”实例中使用了前面章节用到的“XSCJ”数据库,其设计过程在此不再赘述,但要在原“XSCJ”数据库的基础上给每个用户表增加关系、主键、外键和CHECK约束。 1. “学生基本信息表” 在SQL Server 2000企业管理器中所增加的关系、主键和外键如图12-14、图12-15和图12-16所示。
图12-14 “学生基本信息表”的关系、主键和外键 图12-15 “学生基本信息 表”的关系、主键和外键
图12-16“学生基本信息表”的关系、主键和外键图12-16“学生基本信息表”的关系、主键和外键
2. “系部表” “系部表”的主键、外键如图12-17、图12-18所示 图12-17 “系部表”的主键、外键 图12-18 “系部表”的主键、外键
3. “班级表” “班级表”的主键、外键如图12-19、图12-20和图12-21所示。 图12-19 “班级表”的主键、外键 图12-20 “班级表”的主键、外键
图12-21 “班级表”的主键、外键 图12-22 “班级表”的主键、外键
图12-23 “课程信息表”的主键、外键 图12-24 “课程信息表”的主键、外键 4. “课程信息表” “课程信息表”的主键、外键如图12-22、图12-23和图12-24所示。
图12-25 “成绩表”的关系、CHECK约束 图12-26 “成绩表”的关系、CHECK约束 5. “成绩表” “成绩表”的关系、CHECK约束如图12-25、图12-26和图12-27所示。