当前位置:文档之家› VB程序开发技巧汇编

VB程序开发技巧汇编

VB程序开发技巧汇编
VB程序开发技巧汇编

ADO简介 

简介 

 ActiveX Data Objects (ADO) 是微软最新的数据访问技术。它被设计用来同新的数据访问层OLE DB Provider一起协同工作,以提供通用数据访问(Universal Data Access)。OLE DB是一个低层的数据访问接口,用它可以访问各种数据源,包括传统的关系型数据库,以及电子邮件系统及自定义的商业对象。

 ADO向我们提供了一个熟悉的,高层的对OLE DB的Automation封装接口。对那些熟悉RDO的程序员来说,你可以把OLE DB比作是ODBC驱动程序。如同RDO对象是ODBC驱动程序接口一样,ADO对象是OLE DB的接口;如同不同的数据库系统需要它们自己的ODBC驱动程序一样,不同的数据源要求它们自己的OLE DB提供者(OLE DB provider)。目前,虽然OLE DB提供者比较少,但微软正积极推广该技术,并打算用OLE DB取代ODBC。

 ADO向VB程序员提供了很多好处。包括易于使用,熟悉的界面,高速度以及较低的内存占用(已实现ADO2.0的Msado15.dll需要占用342K内存,比RDO的Msrdo20.dll的368K略小,大约是

DAO3.5的Dao350.dll所占内存的60%)。同传统的数据对象层次(DAO和RDO)不同,ADO可以独立创建。因此你可以只创建一个"Connection"对象,但是可以有多个,独立的"Recordset"对象来使用它。

ADO针对客户/服务器以及WEB应用程序作了优化。

 

本文的目的是带你进入ADO广阔的世界并开始使用它。

 

在哪里能得到ADO? 

目前ADO1.5版已经可以从微软网站免费下载。到目前为止,微软网站仍是你获取有关ADO最新信息的最佳场所。ADO1.5是作为OLE DB SDK的一部分提供的。你可以从下面这个网址下载:

http://www.microsoft.com/data/oledb/download.htm

 

在下载之前请先确认OLE DB SDK提供的各项特性。下载文件大约有15M,如果完全安装的话要占用80M的硬盘空间。如果你只对ADO感举趣,就选择最小安装,这样只会占用你15M的硬盘空间。关于ADO的网页在:

 

http://www.microsoft.com/data/ado/adoinfo.htm.

 

在这里你可以找到许多关于ADO的示例代码和文章,尤其是在"Workshop"系列的文章中。你也可以从本站下载ADO2.5的帮助文件。

 

尽管OLE DB SDK提供自己的ADO帮助文件,你会发现ADO1.0的帮助文件更易于使用。同时它还向你提供ADO对象模型的图示

 

ADO是如何组织起来的? 

以前的对象模型,如DAO和RDO是层次型的。也就是说一个较低的数据对象如Recordset是几个较高层次的对象,如Environment和QueryDef,的子对象。在创建一个QueryDef对象的实例之前,你不能创建DAO Recordset对象的实例。但ADO却不同,它定义了一组平面型顶级对象.

最重要的三个ADO对象是Connection, Recordset和Command. 本文将主要介绍Connection和

Recordset这两个对象。每个Connection的属性定义了与数据源的连接。Recordset对象接收来自数据源的数据。Recordset可以与Connection一起起使用,先建立一个连接,然后获取数据。尽管如此,

Recordset也可以被单独创建,其Connection参数可以在Open属性定义。

 

如何使用ADO? 

一旦安装了ADO,在VB的工程->引用对话框中你就可以看到象下图所示的东西了:

 

选择 "ActiveX Data Objects 1.5 Library" (ADODB).在其下的 "ADO Recordset 1.5 Library"是一个客户端的版本(ADOR),它定义了有聚的数据访问对象。ADOR 对于客户端的数据访问来说是足够的了,因为你不需要Connection对象来建立与远程数据源的联系。

 

如果你想要访问更多的外部数据源,你需要安装这些外部数据源自己的OLE DB Provider,就象你需要为新的数据库系统安装新的ODBC驱动程序一样。如果该外部数据源没有自己的OLE DB Provider,你就得使用OLE DB SDK来自己为这个外部数据源创建一个OLE DB Provider了。这已不是本文讨论的范围了。

示例

 

下面的示例代码以Northwinds数据库作为远程数据源,然后用ADO来访问它。首先在控制面板中打开“32位数据源”,单击“添加”按钮。在弹出的对话框中选择 "Microsoft Access Driver (*.mdb)" 作为数据源驱动程序。

 

然后按下图所示,在对话框中填写下面的内容

 

 

选择数据库Northwinds所在路径。单击完成,退出ODBC设备管理器。

 

启动一个新的VB工程,在窗体的Load事件中输入下面的代码:

 

Private Sub Form_Load() 

 

Dim cn As ADODB.Connection 

Set cn = New ADODB.Connection 

 

'Set Connection properties 

cn.ConnectionString = "DSN=RDC Nwind;UID=;PWD=;" 

cn.ConnectionTimeout = 30 

cn.Open 

 

If cn.State = adStateOpen Then _ 

MsgBox "Connection to NorthWind Successful!" 

 

cn.Close 

 

End Sub 

按F5运行程序,看看,一个消息框弹出来告诉你连接成功了。请注意,这里我特别注明了是

ADODB.Connection,而不是ADOR.Connection,这样做是为了将二者区分开(如果你引用了ADODB和ADOR的话,这样做很有必要)。连接字符串看上去同RDO的连接字符串差不多。事实上,二者确实差不多。 如果我们要访问一个SQL server数据库,你的Connection代码看上去应象下面所示:

 

'设置连接属性cn.Provider = "MSDASQL" 

cn.ConnectionString = "driver={SQL Server};" & "server=prod1;uid=bg;pwd=;database=main" 

cn.Open 

 

"Provider"属性指向SQL Server的OLE DB Provider.

回到我们的示例程序,让我们创建一个Recordset对象来访问“Orders”表,并从该表的"ShipCountry"字段中产生头十个不重复的国家名。修改窗体Load事件中的代码,让它看上去象下面这样。

 

Private Sub Form_Load() 

 

Dim cn As ADODB.Connection 

Dim rs As ADODB.Recordset 

 

Dim sSQL As String 

Dim sOut As String 

Dim Count As Integer 

Set cn = New ADODB.Connection 

Set rs = New ADODB.Recordset 

 

' Set properties of the Connection. 

cn.ConnectionString = "DSN=RDC Nwind;UID=;PWD=;" 

cn.ConnectionTimeout = 30 

cn.Open 

 

If cn.State = adStateOpen Then _ 

MsgBox "Connection to NorthWind Successful!" 

 

sSQL = "SELECT DISTINCT Orders.ShipCountry FROM Orders" 

Set rs = cn.Execute(sSQL) 

 

'Enumerate the recordset 

sOut = "" 

For Count = 1 To 10 

sOut = sOut & rs("ShipCountry") & vbCrLf 

rs.MoveNext 

Next Count 

 

MsgBox sOut, vbExclamation, "ADO Results" 

cn.Close 

 

End Sub 

运行程序后,你会看到如下图所示的消息框。

 

不幸的是,目前这个Recrodset对象是只读的和forward cursor。如果你想要获取更多的功能,你需要创建一个独立的Recordset对象,该对象拥有自己的Connection属性,就象下面的代码所示:

 

Private Sub Form_Load() 

 

Dim rs As ADODB.Recordset 

 

Dim sSQL As String 

Dim sOut As String 

Dim Count As Integer 

Set rs = New ADODB.Recordset 

 

sSQL = "SELECT DISTINCT Orders.ShipCountry FROM Orders" 

 

rs.Open sSQL, "DSN=RDC Nwind;UID=;PWD=;", adOpenDynamic 

 

'Report Recordset Connection information 

MsgBox rs.ActiveConnection, , "Connection Info" 

 

'Enumerate the recordset 

sOut = "" 

For Count = 1 To 10 

sOut = sOut & rs("ShipCountry") & vbCrLf 

rs.MoveNext 

Next Count 

 

MsgBox sOut, vbExclamation, "ADO Results" 

 

rs.Close 

 

End Sub 

上面代码返回的结果同前例一样,但是本代码中的Recordset是独立的。这一点是DAO和RDO做不到

的。Recordset对象的Open方法打开一个代表从SQL查询返回的记录的游标。虽然你可以用Connection对象同远程数据源建立连接,但请记住,在这种情况下,Connection对象和Recordset对象是平行的关系。

总结 

本文仅向你介绍了ADO强大的功能的冰山一角。微软承诺,在将来ADO将会取代DAO和RDO。所以现在你应该考虑如何将你的数据访问代码投向ADO的怀抱。这种转变不会很痛苦,因为ADO的语法同现有的语

法差不多。也许微软或第三方会在将来开发出转换向导来简化这一转换过程。从现在起,你就应开发纯

ADO代码的程序。你也可以继续使用DAO或RDO代码来开发你的程序,但落伍的感觉总是不好的。

 

 

ADO三大对象的属性、方法、事件及常数 

 

Connection对象 

属性 

属性名称 数据类型和用途

Attributes 可读写Long类型,通过两个常数之和指定是否使用保留事务(retainning 

transactions)。常数adXactCommitRetaining表示调用CommitTrans方法时启动一个新事务;常数

adXactAbortRetaning表示调用RollbackTrans方法时启动一个新事务。默认值为0,表示不使用保留事务。

CommandTimeout 可读写Long类型,指定中止某个相关Command对象的Execute调用之前必须等待的时间。默认值为30秒。

ConnectionString 可读写String类型,提供数据提供者或服务提供者打开到数据源的连接所需要的特

定信息

ConnectionTimeout 可读写Long类型,指定中止一个失败的Connection.Open方法调用之前必须等待的时间,默认值为15秒。

CursorLocation 可读写Long类型,确定是使用客户端(adUseClient)游标引擎,还是使用服务器端

(adUseServer)游标引擎。默认值是adUseServer。

DefaultDatabase 可读写String类型,如果ConnectString中未指定数据库名称,就使用这里所指定的名称,对SQL Server而言,其值通常是pubs

IsolationLevel 可读写Long类型,指定和其他并发事务交互时的行为或事务。见IsolationLevel常数 Mode Long类型,指定对Connection的读写权限。见Mode常数

Provider 可读写String类型,如果ConnectionString中未指定OLE DB数据或服务提供者的名称,就使用这时指定的名称。默认值是MSDASQL(Microsoft OLE DB Provider for ODBC)。

State 可读写Long类型,指定连接是处于打开状态,还是处于关闭状态或中间状态。见State常数

Version 只读String类型,返回ADO版本号。

 

注意:上面所列出的大多数可读写的属性,只有当连接处于关闭状态时才是可写的。 

 

只有当用户为Connection对象用BeginTrans...CommitTrans...RollbackTrans方法定义了不遗余力,事务隔离程度的指定才真正有效。如果有多个数据库用户同时执行事务,那么应用程序中必须指定如何响应运行中的其他事务。 

 

方法 

方法 用途

BeginTrans 初始化一个事务;其后必须有CommitTrans和/或RollbackTrans相呼应

Close 关闭连接

CommitTrans 提交一个事务,以完成对数据源的永久改变(要求使用之前必须调用了BeginTrans方法) Execute 人SELECT SQL语句返回一个forward-only Recordset对象,也用来执行那些不返回Recordset语句,如INSERT、UPDATE、DELETE查询或DDL语句

Open 用连接字符串来打开一个连接

OpenSchema 返回一个Recordset对象以提供数据源的结构信息(metadata)

RollbackTrans 取消一个事务,恢复对数据源做的临时性改变(要求使用之前必须调用了BeginTrans方法)

 

注:只有Execute、Open和OpenSchema三个方法才能接受变元参数。Execute的语法为: 

cnnName.Execute strCommand,[lngRowsAffected[,lngOptions]] 

strCommand的值可以是SQL语句、表名、存储过程名,也可以是数据提供者所能接受的任意字符串。为了提高性能,最好为lngOptions参数指定合适的值(详见lngOptions参数用到的常数),以使提供者解释语句时不用再去判定其类型。可选参数lngRowsAffected将返回INSERT、UPDATE或DELETE查询执行以后所影响的数目。这些查询会返回一个关闭的Recordset对象。一个SELECT查询将返回

lngRowsAffected值为0并且返回带有一行或多行内容的打开的forward-only Recordset。 

 

事件 

事件名称 触发时机

BeginTransComplete BeginTrans方法执行以后。 

Private Sub cnnName_BeginTransComplet(ByVal TransactionLevel As Long,ByVal pError As 

ADODB.Error,adStatus As ADODB.EventStatusEnum, ByVal pConnection As ADODB.Connection)

CommitTransComplete CommitTrans方法执行以后 

Private Sub Connection1_CommitTransComplete(ByVal pError As ADODB.Error, adStatus As 

ADODB.EventStatusEnum, ByVal pConnection As ADODB.Connection)

ConnectComplete 成功建立到数据源的Connection之后 

Private Sub Connection1_ConnectComplete(ByVal pError As ADODB.Error, adStatus As 

ADODB.EventStatusEnum, ByVal pConnection As ADODB.Connection)

Disconnect Connection关闭之后 

Private Sub Connection1_Disconnect(adStatus As ADODB.EventStatusEnum, ByVal pConnection As ADODB.Connection)

ExecuteComplete 完成Connection.Execute或Command.Execute之时 

Private Sub Connection1_ExecuteComplete(ByVal RecordsAffected As Long, ByVal pError As 

ADODB.Error, adStatus As ADODB.EventStatusEnum, ByVal pCommand As ADODB.Command, ByVal 

pRecordset As ADODB.Recordset, ByVal pConnection As ADODB.Connection)

InfoMessage 一个Error对象被添加到ADODB.Connectio.Error集合之时 

Private Sub Connection1_InfoMessage(ByVal pError As ADODB.Error, adStatus As 

ADODB.EventStatusEnum, ByVal pConnection As ADODB.Connection)

RollbackTransComplete RollbackTrans方法执行之后 

Private Sub Connection1_RollbackTransComplete(ByVal pError As ADODB.Error, adStatus As 

ADODB.EventStatusEnum, ByVal pConnection As ADODB.Connection)

WillConnect 即将调用Connection.Open方法之时 

Private Sub Connection1_WillConnect(ConnectionString As String, UserID As String, Password As String, Options As Long, adStatus As ADODB.EventStatusEnum, ByVal pConnection As 

ADODB.Connection)

WillExecute 即将调用Connection.Execute或Command.Execute方法之时 

Private Sub Connection1_WillExecute(Source As String, CursorType As ADODB.CursorTypeEnum, LockType As ADODB.LockTypeEnum, Options As Long, adStatus As ADODB.EventStatusEnum, ByVal pCommand As ADODB.Command, ByVal pRecordset As ADODB.Recordset, ByVal pConnection As 

ADODB.Connection)

 

注:其中的adStatus参数所用到的常数的名称和含义详见adStatus所用的常数 

 

常数 

 

IsolationLevel常数 

 

常数 含义

adXactCursorStability 只允许读其他事务已提交的改变(默认值)

adXactBrowse 允许读其他事务未提交的改变

adXactChaos 本事务不会覆盖其他位于更高隔离程度的事务所做的改变

adXactIsolated 所有事务相互独立

adXactReadCommitted 等同于adXactCursorStability

adXactReadUncommitted 等同于adXactBrowse

adXactRepeatableRead 禁止读其他事务的改变

adXactSerializable 等同于adXactIsolated

adXactUnspecified 不能确定提供者的事务隔离程度

 

Mode常数 

 

常数 含义

adModeUnknown 未指定数据源的连接许可权(默认值)

adModeRead 连接是只读的

adModeReadWrite 连接是可读写的

adModeShareDenyNone 不拒绝其他用户的读写访问(Jet OLE DB Provider的默认值)

adModeShareDenyRead 拒绝其他用户打开到数据源的读连接

adModeShareDenyWrite 拒绝其他用户打开到数据源的写连接

adModeShareExclusive 以独占方式打开数据源

adModeWrite 连接是只写的

 

State常数 

 

常数 含义

adStateClosed Connection(或其他对象)是关闭的(默认值)

adStateConnecting 正在连接数据源的状态

adStateExecuting Connection或Command对象的Execute方法已被调用

adStateFetching 返回行(row)到Recordset对象

adStateOpen Connection(或其他对象)是打开的(活动的)

 

Execute方法中lngOption参数用到的常数 

 

Command类型常数 含义

adCmdUnknown Command类型未定(默认值),由数据提供者去判别Command语法

adCmdFile Command是和对象类型相应的文件名称

adCmdStoredProc Command是存储过程名称

adCmdTable Command是能产生内部SELECT * FROM TableName查询的表名称

adCmdTableDirect Command是能直接从表中获取行内容的表名称

adCmdText Command是一条SQL语句

 

ADODB事件处理子过程参数adStatus所用的常数 

 

常数 含义

adStatusCancel 操作被用户取消

adStatusCnatDeny 操作不能拒绝其他用户对数据源的访问

adStatusErrorsOccurred 操作导致错误并已送到Errors集合中

adStatusOK 操作成功

adStatusUnWantedEvent 操作过程中一个未预料到的事件被激活

 

 

Command对象 

Command对象的主要目的是执行参数化的存储过程。其形式要么是临时准备(prepared),要么是持久的预编译(precompiled)过的SQL语句。如果想(存储)一个或多个查询以供在同一Connection上多次执行,Command对象也是很有用的。当想创建Recordset时,一种高效的方法是绕过Command对象而采用Recordset.Open方法。

属性 

属性名称 数据类型和用途

ActiveConnection 指针类型,指向Command所关联的Connection对象。对于现存的已打开连接,可使用Set cmmName.ActiveConnection=cnnName。另外,也可以不用相关Connection对象名称而使用有效的连接字符串去创建一个新的连接。默认值为Null。

CommandText 可读写String类型。为ActiveConnection指定一条SQL语句、表名、存储过程名或提供者能接受的任意字符串。CommandType属性的值决定了CommandText属性值的格式。默认值为空字符串:""

CommandTimeout 可读写Long类型,指定中止一个Command.Execute调用之前必须等待的时间。这时的值优先于Connection.ComandTimeout中的设定值。默认值为30秒。

CommandType 可读写Long类型,指定数据提供者该如何解释CommandText属性值。CommandType等效于Connection.Execute方法中的可选参数lngOption。详见CommandType所用到的常数。默认值为

adCmdUnkown.

Name 可读写String类型,指定Command的名称。

Prepared 可读写Boolean类型,判断数据源是否把CommandText中的SQL语句编译为prepared 

statement(一种临时性存储过程)。prepared statement仅存活于Command的ActiveConnection生命周期中。许多客户/服务器RDBMS,包括SQL SERVER,都支持prepared statement。如果数据源不支持prepared statement,则把该属性设为True,将导致一个自陷错误。

State 可读写Long类型,指定Commnad状态。见State常数。

 

注意:最好每次都为CommandType指定的一个合适的常数值,否则会降低系统运行的效率。 

 

方法 

 

方法 用途

Createparameter 在执行该方法之前,必须首先声明一个ADODB.Parameter对象。调用语法为: 

cmmName.CreateParameter [strName[,lngType[,lngDirection[,lngSize[,varValue]]]]]

Execute 调用语法同Connection.Execute大致相同。

 

常数 

 

State常数 

 

常数 含义

adStateClosed Connection(或其他对象)是关闭的(默认值)

adStateConnecting 正在连接数据源的状态

adStateExecuting Connection或Command对象的Execute方法已被调用

adStateFetching 返回行(row)到Recordset对象

adStateOpen Connection(或其他对象)是打开的(活动的)

 

CommandType所用到的常数 

 

Command类型常数 含义

adCmdUnknown Command类型未定(默认值),由数据提供者去判别Command语法

adCmdFile Command是和对象类型相应的文件名称

adCmdStoredProc Command是存储过程名称

adCmdTable Command是能产生内部SELECT * FROM TableName查询的表名称

adCmdTableDirect Command是能直接从表中获取行内容的表名称

adCmdText Command是一条SQL语句

 

 

Recordset对象 

 

属性 

属性名称 数据类型和用途

AbsolutePage 可读写Long类型,要么是设置或返回当前记录所处的页面序号,要么是一个

PositionEnum常数,见AbsolutePage用到的常数。在获取或设置AbsolutePage的值之前,必须先设定PageSize的值。AbsolutePage是从1开始计数的。如果当前记录位于第一页时,AbsolutePage的返回值为1,对AbsolutePage设置将使当前记录指针指向指定页的第一条记录。

AbsolutePosition* 可读写的Long类型(从1开始计数),设置或返回当前记录年处的位置。

AbsolutePosition的最大取值是RecordCount属性的值。

ActiveCommand 可读写的String类型,Recordset所关联的先前打开的Command对象名称

ActiveConnection 指针类型,指向Recordset所关联的先前打开的Connection对象,或指向一条完整有效的ConnectionString串值。 

BOF* 只读Boolean类型,若为True,表明记录指针已位于Recordset第一条记录之前,并且没有了当前记录

Bookmark* 可读写Variant类型,返回对特定记录的引用或使用一个Bookmark值使记录指针指向特定记录

CacheSize* 可读写Long类型,指定本地Cache中所存的记录条数,最小(默认值)为1。若增加了

CacheSize的值,则在流动Recordset以获取更多记录时,能减少与服务器的通信次数。

CursorLocation 可读写Long类型,指定可流动游标的位置,即CursorType是位于客户端还是位于服务器端,见CursorLocation用到的常数。默认值是使用OLE DB数据源提供的游标。

CusrsorType* 可读写Long类型,指定Recordset游标的类型,见CursorType用到的常数,默认值是

forward-only游标

DataMember 指针类型,指向关联的DataEnvironment.Command对象

DataSource 指针类型,指向关联的DataEnvironment.Connection对象

EditMode* 只读Long类型,返回Recordset的编辑状态,见EditMode用到的常数

EOF* 只读Boolean类型,若为True,表明记录指针已超出Recordset的最后一条记录,并且没有了当前记录。

Filter* 可读写Variant类型,要么是一条件表达式(一条有效的SQL WHERE子句但又不出现保留字

WHERE),要么是指向特定记录的Bookmark数组,要么是一个Filter常数,详见Filter用到的常数。 LockType* 可读写Long类型,指定打开Recordset所使用的记录锁定方法。默认值是只读,对应于

forward-only游标的只读特性。见LockType属性用到的常数。

MarshalOptions 可读写Long类型,指定客户端改动后,应返回哪个记录集合,此属性仅适合于不常见

的ADOR.Recordset对象,此对象是RDS.ADOR.Recordset对象成员之一。

MaxRecords* 可读写Long类型,指定SELECT查询或存储过程返回的最大记录条数,默认值为0,即全部返回

PageCount 只读Long类型,返回Recordset所有的页数,必须设定了PageSize的值,PageCount的返回值才是真正有意义的。如果Recordset不支持PageCount属性,则返回值为-1

PageSize 可读写Long类型,设置或返回一个逻辑页所包含的记录条数。使用逻辑页可把大的Recordset分解为多个易处理的小部分。通常的做法是把PageSize设为DataGrid、MsFlexGrid或层次型的

FlexGrid控件所能显示的记录条数。PageSize和锁定Jet(2k)或锁定SQL Server(6.5版及更早版

本,2k;7.0版,8k)数据库时用到的表页面大小无关

PersistFormat 可读写Long类型,设置或返回由调用Save方法所创建的Recordset文件的格式。当前

仅有一个值adPersistADTG(默认格式:Advanced Data TableGram)

RecordCount* 只读Long类型,如果Recordset支持近似定位或支持书签,则返回带可流动游标的

Recordset所含有的记录数;如果不支持,必须使用MoveLast方法以取得确实覆盖了所有记录的准确的

RecordCount数值。如果forward-only类型Recordset有一条或多条记录,Recordset返回-1(True),任何类型的空的Recordset都将返回0(False)

Sort* 可读写String类型,包含一条不含保留字ORDER BY的SQL ORDERY BY子句,用以指定Recordset的排序方式

Source* 可读写String类型,可以是SQL语句、表名、存储过程名或相关Command对象名。如果提供了Command对象名,则Source将返回Command.CommandText的值。利用Open方法的参数lngOptions可以

指定提供给Source值的类型

State 可读写Long类型,为对象状态常数之一。见State常数

Status 只读Long类型,表明对Recordset进行批处理或其他多记录(bulk)操作后的状态。见Status属性用到的常数

 

注意:上表所列属性是ADODB.Recordset对象的标准属性,即那些被关系数据库的大多数通用OLE DB数据提供者所支持的属性。带星号的属性表示它与DAO.Recordset或rdoResultset对象的相应属性完全一样或很接近。

 

方法 

 

方法 用途

AddNew* 向可更新的Recordset添加一条新记录。调用语法为

rstName.AddNew[{varField|avarFields},{varValue|avarValuese}],其中varField是单个字段名,

avarFields是字段名数组。varValue是单个字段值,avarValue是由avarFields指定字段的值所组成的数组。调用Update方法则把新记录加到数据库的表中。如果向主关键字不是第一个字段的Recordset中添加记录,则必须在AddNew方法中指定主关键字的名称和值

Cancel 取消异步查询的执行,中止存储过程或复合SQL语句创建多个Recordset,调用语法为

rstName.Cancel

CancelBatch* 取消LockEdit值为BatchOptimistic的Recordset的即将生效的批量更新操作,调用语

法为:rstName.CancelBatch [lngAffectRecords],可选参数lngAffectRecords的取值见

lngAffectRecords用到的常数

Clone 复制一个带有独立记录指针的Recordset对象,调用语法为:Set rstDupe=rstName.Clone()

Close 关闭Recordset对象,以后可以重新设Recordset的属性并使用Open方法来再度访问

Recordset 。调用语法为:rstName.Close

Delete* 如果Recordset的LockEdit属性值未设为adLockBatchOptimistic,立刻从Recordset和相应表中删除当前记录

Find 寻找满足指定条件的记录。调用语法为:rstName.Find strCriteria [,lngSkipRecords, 

lngSearchDirection [,lngStart]],其中strCriteria是不含WHERE关键字的SQL WHERE子句,可选参

数lngSkipRecords是应用Find前所跳过的记录数目,lngDirection指定查找方向(adSearchForward,和adSearchBackward,其中adSearchForward是默认值),可选参数lngStart指定了从哪儿开始查找,其值

要么是一个Bookmark值,要么是Bookmark常数,见varStart参数用到的Bookmark常数。

GetRows 返回一个二维Variant数组(行、列),调用语法为avarname=rstName.GetRows(lngRows 

[,varStart[,{strFieldName|lngFieldIndex|avarFieldNames|avarFieldIndexes}]],其中lngRows是返回记录行数,varStart指定从哪儿开始查找,其值要么是一个Bookmark值,要么是Bookmark常数,见varStart参数用到的Bookmark常数。第三个参数可以是单个列(字段)的名称或索引,也可以是多个列名称或索引组成的Variant数组。如果不指定第三个参数,GetRows返回Recordset中所有列。

GetString 默认情况下,返回指定数目记录的String串值,记录间由返回代码分隔。记录内由tab分隔。调用语法为: strClip=rstname.GetString(lngRows,[, 

strCloumnDelimiter[,strRowDelimiter,[strNullExpr]]])。其中lngRows为返回记录行数,

strColumnDelimiter为可选的列分隔符(vbTab是默认值),strRowDelimiter是可选的行分隔符(vbCr是

默认值),strNullExpr是可选参数,用于碰到Null值时的替代值(默认值是空字符串)。GetString的主要用途是通过把控件的Clip属性设为strClip来处理MSFlexGrid或MSHFlexGrid控件

Move* 从当前记录移动记录指针。调用语法为:rstName.Move lngNumRecords [, varStart],其中

lngNumRecords是要跳过的记录数,可选选参数varStart指定从哪开始移动。其值要么是一个Bookmark值,要么是Bookmark常数,见varStart参数用到的Bookmark常数。

MoveFirst* 移动记录指针到第一条记录,调用语法为:rstName.MoveFirst

MoveLast* 移动记录指针到最后一条记录,调用语法为:rstName.MoveLast

MoveNext 移动记录指针到下一条记录,调用语法为:rstName.MoveNext。它是能用于forward-only 

Recordset的唯一Move方法

MovePrevious* 移动记录指针到前一条记录,调用语法为:rstName.MovePrevious

NextRecordset 返回另外的Recordset,它通常由能产生多个Recordset的复合SQL语句(如SELECT * 

FROM orders;SELECT * FROM customers)或存储过程来创建。调用语法为Next=rstName.NextRecordset [(lngRecordsAffected)],其中可选参数lngRecordsAffected指定返回到rstNext中去的记录数目。如

果已不存在Recordset,rstNext被设为Nothing

Open 在一个活动Command或Connection对象上打开一个Recordset,调用语法为:rstName.Open 

[varSource [, varActiveConnection [, lngCursorType [, lngLockType [, lngOptions]]]]]。这些

参数都是可选的,

Requery 重新从表中获取Recordset的内容,等效于Close后再Open。它是一个资源集中型操作。语法为:rstName.Requery

Resync* 重新从表中获取部分Recordset内容。调用语法为rstName.Resync [lngAffectRecords],其中lngAffectRecords的取值见lngAffectRecords用到的常数。如果把该参数设为adAffectCurrent或

adAffectGroup,则比adAffectAll(默认值)所耗的资源要少。

Save 创建包含Recordset永久性拷贝的文件。调用语法为rstName.Save strFileName。其中

strFileName为路径和文件名。通常用.rst作为文件的扩展名。

Supports 如果数据提供者支持指定的游标相关的方法,则返回True,否则返回为False。调用语法为

Supported=rstname.Supports (lngCursorOptions).关于lngCursorOptions,见Supports方法用到的常数。

Update* 使对Recordset的修改对底层数据源中的表生效。对于批量操作,Update方法只使修改对本地(Cached)Recordset生效。调用语法为rstName.Update

UpdateBatch* 合对指量类型的Recordset(LockType属性值为adBatchOptimistic,CursorType属性值为adOpenKeyset或adOpenStatic)所做的修改对底层数据源中的表生效。调用语法为rstName.UpdateBatch [lngAffectRecords],其中lngAffectRecords的取值见lngAffectrecords用到的常数。

 

注:ADODB.Recordset对象不支持Edit方法。为了改变ADODB.Recordset对象当前记录的一个或多个字段的值,可以先使用rstName.Fields(n).Value=varValue把相应字段的值改为所需要的值,而后执行rstName.Update即可。 

 

事件 

 

事件名称 触发时机

EndOfRecordset 记录指针试图移到最后一条记录之外时

FieldchangeComplete 字段值的改变完成之后

MoveComplete Move或Move...方法执行之后

RecordsChangeComplete 对单个记录编辑完成以后

RecordsetChangeComplete 缓存中的改变对底层表生效之后

WillChangField 对字段值改变之前

WillChangeRecord 对单个记录改变之前

WillChangeRecordset 缓存中的改变对底层表生效之前

WillMove Move或Move...方法执行之前

 

注:事件处理模块的函数头几乎都用到了adReason参数。该参数的取值见adReason参数用到的常数。

常数 

 

AbsolutePage属性用到的常数 

 

常数 含义

adPosUnknown 数据提供者不支持页面,Recordset为空,或数据提供者不能确定页码。

adPosBOF 记录指针定位于文件开头(BOF属性值为True)

adPosEOF 记录指针定位于文件结尾(EOF属性值为True)

 

CursorLocation属性用到的常数 

 

常数 含义

adUseClient 使用客户端游标库提供的游标。ADODB.Recordset要求客户端游标

adUseServer 使用数据源提供的游标,通常(但非绝对)位于服务器上(默认值)

 

CursorType属性用到的常数 

 

常数 含义

adOpenForwardonly 提供单向移动游标和只读Recordset(默认值)

adOpenDynamic 提供可滚动游标,可显示其他用户对Recordset所做的改动(包括添加新记录)

adOpenKeyset 提供可滚动游标,只隐藏其他用户所做的改动,类似于dynaset类型的DAO.Recordset adOpenStatic 提供一个位于Recordset静态拷贝上的可滚动游标,类似于snapshot类型的

DAO.Recordset,但多了可更新特性

 

EditMode属性用到的常数 

 

常数 含义

adEditNone 无正在进行的编辑操作(默认值)

adEditAdd 临时添加一条记录,但尚未存入数据库的表中

adEditInProgress 当前记录中的数据已经改动,但尚未存入数据库的表中

 

 

常数 含义

adFilterNone 除去已有的过滤器,显示Recordset中的所有记录(等效于把Filter属性置为空串,默认值)

adfilterAffectedRecords 只显示上次CancelBatch、Delete、Resync或UpdateBatch方法执行后所影响的记录

adFilterFetchedRecords 只当前Cache中的记录,记录条数由CacheSize来确定

adFilterPendingRecords 只显示已改动但尚未被数据源处理的记录(仅适用于批量更新模式)

 

LockType属性用到的常数 

 

常数 含义

adLockRecordOnly 指定只读访问(默认值)

adLockBatchOptimistic 使用批量更新模式而不是默认的立即更新模式

adLockOptimistic 使用乐观锁(仅在更新过程中才锁定记录或页面)

adLockPessimistic 使用悲观锁(编辑或更新整个过程中均锁定记录或页面)

 

State常数 

 

常数 含义

adStateClosed Connection(或其他对象)是关闭的(默认值)

adStateConnecting 正在连接数据源的状态

adStateExecuting Connection或Command对象的Execute方法已被调用

adStateFetching 返回行(row)到Recordset对象

adStateOpen Connection(或其他对象)是打开的(活动的)

 

Status属性用到的常数(仅适用于Batch或Bulk Recordset操作) 

 

常数 含义

adRecOK 成功更新

adRecNew 成功添加

adRecModified 成功修改

adRecDeleted 成功删除

adRecUnmodified 无改动

adRecInvalid 未保存:Bookmark属性无效

adRecMultipleChanges 未保存:保存会影响其他记录

adRecPendingChanges 未保存:记录引用了一个等待插入操作

adRecCanceled 未保存:操作被取消

adRecCantRelease 未保存:现有记录值阻止了保存

adRecConcurrencyViolation 未保存:乐观并发锁发生了问题

adRecIntegrityViolation 未保存:操作会影响一致性

adRecMaxChangesExceeded 未保存:存在太多的等待改动

adRecObjectOpen 未保存:打开存贮对象发生冲突

adRecOutofMemory 未保存:内存不足

adRecPermissionDenied 未保存:用户权限不够

adRecSchemaViolation 未保存:记录的结构不符合数据库中的定义

adRecDBDeleted 未保存或删除:记录已被删除

 

lngAffectRecords参数用到的常数 

 

adAffectAll 包括Recordset对象的所有记录,那些被Filter属性过滤隐藏的记录也计算在内(默认值)

adAffectCurrent 只包括当前记录

adAffectGroup 只包括那些符合当前Filter条件的记录

 

varStart参数用到的Bookmark常数 

 

常数 含义

adBookmarkCurrent 从当前记录开始(默认值)

adBookmarkFirst 从第一条记录开始

adBookmarkLast 从最后一条记录开始

 

 

Supports方法用到的常数 

 

常数 含义

adAddNew 调用AddNew方法

adApproxPosition 设置和得到Absoluteposition和AbsolutePage属性值

adBookmark 设置和得到Bookmark属性值

adDelete 调用Delete方法

adHoldRecords 获取另外的记录或改变获取记录指针的位置,但不提交未确定的改变

adMovePrevious 调用GetRows,Move,MoveFirst和MovePrevious方法(表明是一个双向可滚动游标) adResync 调用Resync方法

adUpdate 调用Update方法

adUpdateBatch 调用UpdateBatch和CancelBatch方法

 

 

adReason参数用到的常数 

 

常数 含义

AdRsnAddNew 调用了AddNew方法

AdRsnClose 调用了Close方法

AdRsnDelete 调用了Delete方法

AdRsnFirstChange 第一次对记录字段值做了修改

AdRsnMove 调用了Move方法

AdRsnMoveFirst 调用了MoveFirst方法

AdRsnMoveLast 调用了MoveLast方法

AdRsnMovePrevious 调用了MovePrevious方法

AdRsnRequery 调用了Requery方法

AdRsnResync 调用了Resync方法

AdRsnUndoAddNew AddNew操作被用户取消

AdRsnUndoDelete Delete操作被用户取消

AdRsnUndoUpdate Update操作被用户取消

AdRsnUpdate 调用了Update方法

 

 

 

 

Visual Basic 的数据库编程作者:孙志刚

 

 

 Visual Basic作为应用程序的开发“利器”也表现在数据库应用程序的开发上,它良好的界面和强大的控件功能使数据库编程变得简单多了。但即便如此,数据库应用程序的开发仍然算得上是VB编程中的难点,这是因为你不仅要熟悉VB中关于数据库编程方面的知识(当然这是十分简单的)还要了解数据库的知识。所以我们先介绍一下数据库的基本知识,算是学习数据库编程前的热身运动吧! 

 

一、热身运动 

首先需要声明是,我们这里介绍的数据库知识都是指的关系数据库。所谓关系数据库就是将数据表示为表的集合,通过建立简单表之间的关系来定义结构的一种数据库。 

不管表在数据库文件中的物理存储方式如何,它都可以看作一组行和列,与电子表格的行和列类似。在关系数据库中,行被称为记录,而列则被称为字段。下面是一个客户表的例子。 

表1 客户表

客户号 姓名 地址 城市 街道 邮编

1723 Doe John 1234 Ffth Avenue New York NY 1004

3391 Smith Mary 9876 Myrtle Lavee Bosten MA 6078

3765 Blasel Mortimer 2296j River Road peoria IL 7011

 

此表中每一行是一个记录,它包含了特定客户的所有信息,而每个记录则包含了相同类型和数量的字段:客户号、姓名等等。 

表 是一种按行与列排列的相关信息的逻辑组,类似于工作单表。 

字段 数据库表中的每一列称作一个字段。表是由其包含的各种字段定义的,每个字段描述了它所含有的数据。创建一个数据库时,须为每个字段分配一个数据类型、最大长度和其它属性。字段可包含各种字符、数字甚至图形。 

记录 各个客户有关的信息存放在表的行,被称为记录。一般来说,数据库表创建时任意两个记录都不能相同。 

键 键就是表中的某个字段(或多个字段),它(们)为快速检索而被索引。键可以是唯一的,也可以是非唯一的,取决于它(们)是否允许重复。唯一键可以指定为主键,用来唯一标识表的每行。例如,在前面的例子中,客户标识号 (客户号) 是表的主键,因为客户号唯一地标识了一个客户。 

关系 数据库可以由多个表组成,表与表之间可以以不同的方式相互关联。例如,客户数据库还可以有一个包含某个客户的所有定单的表。它只用“客户号”字段来引用该定单的客户,而不在定单表中的每项重复所有客户信息,如下表所示: 

表2 定货表 

 

定货 客户号 日期 内容 数量

14764 3391 2/23/94 27 ¥22.95

14932 3391 3/17/94 46 ¥9.57

15108 8765 2/15/96 27 ¥22.95

 

在这个表中,客户号字段引用了客户表中的 客户号字段,从而把定单和客户联系起来了。可以看到,客户 3391 (Mary Smith) 在 94 年 2 月 23 日订购了 27 项,在 94 年 3 月 17 日订购了 46 项。用来建立关系的键叫做外部键,因为它与“外部”表(客户表)的主键关联。 

一对多和多对多关系 上表中的关系类型叫做一对多关系,因为一个客户可以发出多个定单,而某个特定的定单只能是一个客户所发。也可以建立多对多的关系。例如,列出所有可以销售的项(存货)的盘存表: 

表3 盘存表 

 

内容 描述 供应商 费用 盘存

27 Straw Hat Garden Supply Co. ¥14.00 50

46 Garden gloves Garden Supply Co. ¥4.50 75

102 hanging floral industries ¥6.00 137

 

从盘存表中,可以看到在客户和存货项之间存在多对多的关系。也就是说,一个客户可以订购多个存货项,而一个存货项又能够被多个客户订购。多对多关系是通过两个独立的一对多关系来定义的,公共的“多”表包含了两个其它表的外部键。在该例中,定货s 表与 盘存 表(通过 “内容”)与 

Customer 表(通过 客户号)都相关联。通过这三个表,我们可以看到,Mary Smith (客户号 3391) 订购了 Straw Hat (“内容” 27) 和Garden Gloves (“内容” 46),而 Mary Smith (客户号 3391) 和 Mortimer Blaselflatz (客户号 8765) 都订购了Straw Hat (“内容” 27)。如果把客户表和盘存表的相关字段与 定货表的“定货”字段联结起来,建立一个“关联”表,那么这个关系就更清楚了。 

表4 关联表:按客户号和内容排序 

 

定货号 客户号 姓名 内容 描述

14764 33391 Smith Mary 27 Straw Hat

14932 33391 Smith Mary 46 Garden Gloves

15168 8765 Blaselfatz Mortimer 27 Straw Hat

 

规范化 数据库设计者的任务就是组织数据,而组织数据的方法,应能消除不必要的重复,并为所有必要信息提供快速查找路径。为了达到这种目标而把信息分离到各种独立的表中去的过程,叫作规范化。 

规范化是用许多指定的规则和不同级别的范式来进行规范的复杂过程。该过程的研讨已超出了本文的范围。但是,大多数简单数据库的规范化可以用下面简单的经验规则来完成:包含重复信息的表必须分成独立的几个表来消除重复。 

例如,使学生和课程对应的学生数据库,包含了下表所示的信息。 

表5 

 

学生 课程 描述 教授

1 4 Introduction to Physiology Dawson

2 3 Applied Basketweaing Carruth

3 1 Physics for Short-定货 cooks Adms

4 2 Introduction to Physiology Dawsons

 

如果有选学了十二门课程的 1000 个学生,每门课程的说明和教师将显示100多次─ 对选了那门课程的每个学生都要重复一次。要避免这种低效率,应当把表分成两个独立的表来规范化,一个用来表示学生,另一个用来表示课程,如表6,表7所示。 

 

 

学生 课程

1 4

2 3

3 1

4 4

课程 描述 教授

1 Physics for Short-定货 cooks Adms

2 Counterculture Sociology Beckely

3 Applied Basketweaing Carruth

4 Introduction to Physiology Dawsons

表6 

表7 

 

现在表被规范化了,所以,要改变特定课程的课程描述或“数据”,只要改变一个记录就可以了。 以上是关于数据库的基本知识,这是学习数据库编程所必须的。虽然数据库技术作为一门学科,其深度

和广度不是这点篇幅能描述的,但作为入门和简单数据库编程应该是足够了。 

好了,下面我们就可以开始练练了。我们经常遇到数据库系统是登记系统,不管你是在单位,或是

参加什么组织,登记是免不了的,而且它的结构比较简单,我们就以一个登记系统为例吧。分析一下该

系统所涉及到的数据。 

 

二、磨刀不误砍柴功 

 

对于登记,要跟踪的信息包括: 

● 姓名 ● 性别 

● 籍贯 ● 年龄 

● 出生年月 ● 单位 

● 地址 ● 邮政编码 

● 电话 ● 传真 

当然,可以简单地创建一个表,使得上述的每个数据项对应一个字段。 

现在需要给表指派主键,用以唯一标识每一条记录,在登记表中分别添加登记号作为唯一键,这样就保证数据库中的任两条记录都不同了。 

对数据库作出以上分析后,我们就可以开始建立数据库了。 

 

三、建营扎寨 

在这里我们学习怎样建立数据库,首先需要确定要建立数据库的类型。在Visual Basic中通过数据访问控件或数据访问对象(DAO)可以访问下列数据库: 

1. JET数据库,即Microsoft Access 

2. ISAM数据库,如:dBase,FoxPro等 

3. ODBC数据库,凡是遵循ODBC标准的客户/服务器数据库。如:Microsoft SQL Server、Oracle 一般来说,如果要开发个人的小型数据库系统,用Access数据库比较合适,要开发大、中型的数据库系统用ODBC数据库更为适宜。而dBase和FoxPro数据库由于已经过时,除非特别的情况,否则不要

使用。在我们的例子中,当然选用Access数据库了。建立Access数据库有两种方法:一是在Microsoft Access中建立数据库。点击“新建”按钮就可以建立新的表了(如图1)。这里我们主要介绍第二种方法:使用可视化数据管理器,不需要编程就可创建数据库。可视化数据管理器是一个非常有用的应用程序,它是VB企业版和专业版附带的,在目录\..\DevStudio\vb\samples\Visdata下,其界面如下图。 点击菜单“文件”项下“新建”子项“Microsoft ACCESS”子项的“版本7.0 MDB”项。在弹出窗口中输入新建数据库的名称“登记”,出现下面图3所示窗口: 

要生成新的表,右键单击数据库窗口弹出菜单,然后选择“新表”命令,在随后出现的“表结构”

对话框中建立所要的字段。每次向表中加入新的字段,单击“增加字段”按钮,会出现图4 的“增加字段”对话框。 

“增加字段”对话框中的选项如表10所示,根据字段的类型,有些选项是无效的,无法读取。 

在我们建立的登记数据库中,各个字段的类型如表11。 

 

要注意的是,由于字段登记号用来唯一标志记录的,因此,它不能由用户输入。所以在定义该字段

时需要定义为Long数据类型,“自动生成字段”项有效,并选中这一项。这样当用户每输入一条新记录时,系统就会在该字段上自动输入一个与其它记录不同的值。 

在ACCESS数据库中,关键字是用索引实现的,作为编程人员在对表类型的记录集编程时,只需调用索引名。在查询时,Rushmore技术自动用索引信息优化查询。完成表定义后,点击“增加索引”按钮,弹出

如图5所示窗口。 

在窗口中右边有三个选项,其意义如表 12。 

添加索引对话框选项 

完成之后如图6。 

当然,学会数据库的建立也并非一朝一夕的事,读者不妨多练习一下。下面你就可以运行VB开始我们的编程了。 

 

四、千里相会 

Visual Basic 数据库应用程序有三个部分,如图7所示。 

用户程序是程序员开发的,也是我们即将用VB来编写的部分。数据库引擎是数据库驱动程序,使用它程序员可以用统一的格式访问各种数据库,不管这个数据库是本地的 Visual Basic 数据库,还是所

支持的其它任何格式的数据库格式,所使用的数据访问对象和编程技术都是相同的。数据库则是我们上

面完成的部分。从这个结构可以看出用户与正在访问的特定数据库无关。那我们在用VB编写数据库程序时,就需要使程序能够访问指定的数据库。 

如果是简单的数据库应用,可以使用 Data 控件来执行大部分数据访问操作,而根本不用编写代

码。与 Data 控件相捆绑的控件自动显示来自当前记录的一个或多个字段的数据。 

 

DATA数据控件 

属性 

CONNECT属性 指定打开的数据库类型,并且包括参数,如用户和口令等。 

例如: 

打开Access数据库(缺省) 

CONNECT=“ACCESS” 

打开ODBC数据库 

CONNECT=“ODBC;DATABASE=??;UID=??;PWD=??;DSN=??” 

DATABASENAME属性 确定数据控件访问哪一个数据库。 

对于多表数据库它为具体的数据库文件名,例如:ACCESS数据库 

DATABASENAME=“D:\...\DEMO.MDB" 

对于单表数据库它为具体的数据库文件所在的目录,而具体文件名放在RECORDSOURCE属性中,例如:访问FOXPRO数据库文件D:\FOX\DEMO.DBF 

DATABASENAME=“D:\FOX” 

RECORDSOURCE=“DEMO”不带文件扩展名 

RECORDSOURCE属性 

确定数据控件的记录集,即:所要访问的数据内容。它可以是一个表名、存储查询名或SQL语句。例如:访问Register表所有数据 : 

RECORDSOURCE=“Register”访问RC表中1973年以前出生的数据: 

RECORDSOURCE=“SELECT *FROM Register WHERE [BIRTHDAY]<#1/1/1973#" 

注意:当我们在运行时修改了该属性后,需要调用REFRESH方法刷新记录集。 

 

方法 

REFRESH方法 当我们在运行时修改了Record- 

Source属性后,需要调用该方法刷新记录集。 

UPDATERECORD方法 将绑定在数据控件上的控件的数据写入数据库中。即:当我们修改了数据后调用该方法确定修改。 

CANCELUPDATE方法 将数据库中的数据重新读到绑定在数据控件上的控件中。即:当我们修改了数据后调用该方法放弃修改。 

 

事件 

VALIDATE事件 当我们移动记录集记录指针时发生。例如:我们将记录集记录指针从A移动到记录B时当产生VALIDATE事件时,记录指针仍在记录A上。 

Sub XXXX_Validate(Action As integer,Save As integer) 

其中: 

Action 指出如何产生了该事件,如:移动,增加,查询等。 

Save 表示是否保存已修改的数据。当我们修改了绑定在数据控件的数据,又没有UPDATERECORD,则移动指针时,Save=True。如果在事件中令Save=False,则放弃修改。 

例如: 

 

Sub XXXX_Validate(Action As integer,Save As integer) 

If Save then 

I= MsgBox("Dada changed,Save?",vbYesNo) 

If I = vbNo then 

Save = False 

End if 

End if 

End Sub 

 

Reposition事件 当我们移动记录集指针时发生。例如:我们将记录集记录指针从A移动到记录B 时,当产生Reposition事件时,记录指针已移动到B上。 

通常我们在该事件中显示当前的指针位置。例如: 

Sub XXXX_Reposition() 

XXXX.Caption=?? 

XXXX.RecordSet.AbsolutePosition + 1 

End Sub 

 

了解了DATA控件之后我们就可以连接数据库了。现在我们可以编写一个应用程序。因为虽然我们建立了Register数据库,但是数据库中却没有数据,我们程序的目的就是向数据库中输入数据。它的运行情况如图8。 

各个文本框正好对应着表Register的各个字段,在文本框中输入数据,点击“增加”按钮,就完成了一条记录的输入。我们看一下,DATA控件是怎样和数据库连接起来的,各个文本框又是怎样和DATA控件捆绑起来的。 

在DATA控件的CONNECT属性中,选中“ACCESS”项,在DatabaseName属性中,输入“C:\TEMP\登记.mdb”,在RecordSource属性中,选中“Register”,这样就完成了数据库与DATA控件的连接,也就是完成了与应用程序的连接。 

 

数据库中各个字段又是怎样和文本框连接起来的呢?在VB中,我们可以将普通控件绑定在数据控件上,来完成自动地显示、更新记录集的数据。常用的可绑定的控件有:Label,Text,checkBox,Image等。通过设置这些控件的DataSource和DataField属性来完成绑定。 

 

DataSource 属性 表示绑定到哪一个数据控件上,程序中我们可能使用多个数据控件。 

DataField 属性 表示绑定到记录集的哪一个记录上。 

现在我们需要把Text1与表“登记”中的姓名字段连接起来。完成DATA控件的连接之后,在Text1控件的DataSource属性中,选中“Data1”,在DataField属性中,选中“姓名”值。用同样的方法,将各个文本框分别绑定到对应的字段上,就完成了文本框的捆绑。 

下面我们编写两个按钮命令,完成其相应的操作了。喂!别着急,还有一个重要的对象没讲呢! 

当应用程序启动时,Data 控件被自动地初始化。如果 Connect、DatabaseName、Options、

RecordSource、Exclusive、ReadOnly 和 RecordsetType 属性是合法的, Microsoft Jet 数据库引擎就会试图创建一个新的基于这些属性的 Recordset 记录集对象。Recordset 对象可以表示表中的记录或者作为查询结果的记录,使用 Recordset 对象可以在记录一级上对数据库中的数据进行处理。这在数据库编程中是一个十分重要的,也是比较复杂的对象。

Recordset 对象有三种类型:表、动态集、快照,它们之间存在明显的区别。 

表类型的 Recordset 对象是指当前数据库中的表在创建表类型的记录集时,数据库引擎打开的表。后续的数据操作都是直接对表进行的。只能对单个的表打开表类型的记录集,而不能对联接或者联合查询打开表类型的记录集。与其它类型的 Recordset 对象相比,表类型的搜索与排序速度最快。 

动态集类型的 Recordset 对象可以是本地的表,也可以是返回的行查询结果。它实际上是对一个或者几个表中的记录的一系列引用。可用动态集从多个表中提取和更新数据,其中包括链接的其它数据库中的表。动态集类型具有一种与众不同的特点:不同数据库的可更新联接。利用这种特性,可以对不同

类型的数据库中的表进行可更新的联接查询。动态集和它的基本表可以互相更新。如果动态集中的记录发生改变,同样的变化也将在基本表中反映出来。在打开动态集的时候,如果其他的用户修改了基本表,那么动态集中也将反映出被修改过的记录。动态集类型是最灵活的Recordset 类型,也是功能最强的。不过,它的搜索速度与其它操作的速度不及表类型的 Recordset。 

快照类型的 Recordset 对象包含的数据是固定的,它反映了在产生快照的一瞬间数据库的状态。从 Microsoft Jet 数据源得到的快照是不可更新的,从开放数据库互连 (ODBC) 数据源得到的某些快照是可以更新的,这取决于数据库系统本身的能力。与动态集类型和表类型的 Recordset 对象相比,快照的处理开销较少。因此,它执行查询和返回数据的速度更快,特别是在使用 ODBC 数据源时。快照类型保存了表中所有记录的完整复本,因此,如 果记录的个数很多,快照的性能将比动态集慢得多。为了确定快照与动态集哪一个更快,可以先以动态集方式打开记录集,然后再以快照方式打开它。 

具体使用什么记录集,取决于需要完成的任务:是要更改数据呢,还是简单地查看数据。例如,如果必须对数据进行排序或者使用索引,可以使用表。因为表类型的 Recordset 对象是做了索引的,它定位数据的速度是最快的。如果希望能够对查询选定的一系列记录进行更新,可以使用动态集。如果在特殊的情况下不能使用表类型的记录集,或者只须对记录进行扫描,那么使用快照类型可能会快一些。 

一般来说,尽可能地使用表类型的 Recordset 对象,它的性能通常总是最好的。 

为选择特定的 Recordset 类型,把 Data 控件的RecordsetType属性设成: 

 

RecordSet记录集属性 

BOF属性 当记录集记录指针指向第一条记录时返回True 

EOF属性 当记录集记录指针指向最后一条记录时返回True 

AbsloutePosition属性 返回当前记录集记录指针,第一条记录为0,是只读属性 

Bookmark属性 String类型,返回或设置当前记录集记录指针的书签,是可读写属性。每一条记录都有自己唯一的书签,它与记录在记录集中的顺序无关。将Bookmark属性存放到变量中,后面可以通过将该变量赋值给Bookmark属性,并返回到这个记录。 

注意:程序中使用BookMark属性重定位记录指针,而不能使用Abslouteposition 

NoMatch属性 当我们使用Find方法查询时如果未找到则返回True。常与BookMark属性同时使用。 

例如:查找[NAME]字段中第一个姓李的人 

 

Dim S As String 

With XXXX.RecordSet 

S = .BookMark 

.FindFirst "[NAME] Like '李*'" 

if .NoMatch then 

MsgBox "数据未找到“ 

.BookMark = S 

End if 

End With 

 

记录集方法 

AddNew方法 向记录集增加一条新记录 

Delete方法 从记录集中将当前记录删除。在删除后常使用MoveNext方法移动指针。 

例如: 

 

With XXXX.RecordSet 

.Delete 

.MoveNext 

if .EOF then .MoveLast 

End With 

 

MoveXXXX方法 

MoveFirst 将记录集指针移动到第一条记录上 

MoveLast 将记录集指针移动到最后一条记录上 

MovePrevious 将记录集指针移动到前一条记录上 

MoveNext 将记录集指针移动到下一条记录上 

FindXXXX方法 

FindFirst在记录集中查询符合条件的第一条记录 

FindLast 在记录集中查询符合条件的最后一条记录 

FindPrevious 在记录集中查询符合条件的前一条记录 

FindNext 在记录集中查询符合条件的下一条记录 

好了,有了这么充分的知识了,编写两个按钮命令简直是小菜一碟,先来试一下,添一个“增加”命令按钮吧。 

 

Private Sub Command1_Click() 

Data1.Recordset.AddNew 

End Sub 

 

哇!怎么这么简单,再看一下“删除”命令按钮 

 

Private Sub Command2_Click() 

Data1.Recordset.Delete 

Data1.Recordset.AddNew 

End Sub 

 

就这样行了吗?运行程序吧,OK!一切正常,迫不及待地输入一条记录,点击“增加”按钮,怎么?出问题了!因为你只有在进行了AddNew方法后才可以输入数据,好吧,在窗口的初始化时就增加一条新记录吧。 

 

Private Sub Form_Initialize() 

Data1.Recordset.AddNew 

End Sub 

输入完了数据,我们打算退出程序,很自然的我们执行关闭窗口操作,就顺利地结束了输入工作。真的很顺利吗?打开数据库,看看数据库中的数据,我们发现刚才输入的最后一条记录没有存入数据库中。这个很好解释,每当我们调用AddNew方法时,它就将输入的记录存入数据库中,而当我们关闭窗口时,刚输入的记录并没有保存到数据库中,那么在关闭窗口之前对DATA控件进行一次刷新就可以将数据存入数据库中了。 

 

Private Sub Form_QueryUnload(Cancel As Inte ger, UnloadMode As Integer) 

Data1.Refresh 

End Sub 

 

到了这里,我们似乎可以稍稍轻松了一点,这个窗口的功能差不多完成了。但是我不得不给你提出一个忠告:在数据库系统中,应尽量将错误在应用级上处理。这句话看起来似乎有点抽象,实际上用在这个程序中就简单多了。在表Register中,我们将出生日期定义为Date/Time类型,如果在程序运行时,在该字段对应的文本框中输入的不是Date/Time格式,在向数据库提交数据时会出现什么情况呢?数据库会向用户报告错误信息。然而这样对应用程序并不好,这样的错误应该由用户程序处理,而不是交给数据库去处理,所以在数据提交之前就应该检查该字段的输入是否合法。 

 

Private Sub Text3_LostFocus() 

If IsDate(Text3.Text) Or Text3.Text = "" Then '检查是否输入合法数据 

Exit Sub 

End If 

MsgBox ("输入错误,请输入你出生的年月日!") 

相关主题
文本预览
相关文档 最新文档