资源预览内容
第1页 / 共81页
第2页 / 共81页
第3页 / 共81页
第4页 / 共81页
第5页 / 共81页
第6页 / 共81页
第7页 / 共81页
第8页 / 共81页
第9页 / 共81页
第10页 / 共81页
亲,该文档总共81页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
第8章 使用DAO访问数据库第8章 使用DAO访问数据库8.1 DAO层次结构层次结构8.2 DAO对象对象8.3 DAO编程实例编程实例8.1 DAO8.1 DAO层次结构层次结构DAO提供两种不同的编程模型结构:提供两种不同的编程模型结构:Microsoft Jet Workspaces DAO模型模型ODBC Direct Workspaces DAO模型。模型。数据访问对象模型是数据访问对象模型是Jet为数据库引擎的面向对象为数据库引擎的面向对象的接口。由一系列数据库对象和对象的集合按的接口。由一系列数据库对象和对象的集合按一定的层次结构组成。其层次结构和关系数据一定的层次结构组成。其层次结构和关系数据库的逻辑视图相符合。数据访问对象类以分层库的逻辑视图相符合。数据访问对象类以分层结构来组织,其中的大多数类属于集合类。在结构来组织,其中的大多数类属于集合类。在分层结构中,它又属于其上层的另一个类。分层结构中,它又属于其上层的另一个类。DAO的层次结构如图的层次结构如图8.1所示。所示。 8.1 DAO8.1 DAO层次结构层次结构图8.1 DAO层次结构模型图8.2 DAO8.2 DAO对象对象8.2.1 DBEngine对象8.2.2 Workspace对象8.2.3 Database对象8.2.4 TableDef对象8.2.5 Recordset对象8.2.6 QueryDef对象8.2.7 Field对象8.2 DAO8.2 DAO对象对象DBEngine对象对象DBEngine对象相当于对象相当于Jet数数据库引擎,它是不需要创据库引擎,它是不需要创建就已经存在的对象,而建就已经存在的对象,而且一个应用界面只能有一且一个应用界面只能有一个个DBEngine对象。对象。DBEngine对象位于对象位于DAO对象的顶层,其层次结构对象的顶层,其层次结构如图如图8.2所示。所示。图8.2 DBEngine对象8.2 DAO8.2 DAO对象对象DBEngine对象的属性对象的属性DefaultUser:缺省用户名称。进行数据:缺省用户名称。进行数据库访问时设置的缺省用户名称,是一个库访问时设置的缺省用户名称,是一个长度小于长度小于20个字符的个字符的String变量,变量,DefaultUser的缺省值是的缺省值是Admin。DefaultPassword:缺省用户口令。进行:缺省用户口令。进行数据库访问时设置的缺省用户口令,数据库访问时设置的缺省用户口令,DefaultPassword的缺省值是空字符串。的缺省值是空字符串。SystemDB:系统数据库名称。本地:系统数据库名称。本地Microsoft Jet数据库工作组文件,缺省值数据库工作组文件,缺省值为为System.mdw8.2 DAO8.2 DAO对象对象IniPath:初始文件位置。设置或返回:初始文件位置。设置或返回Windows注册文件中存有注册文件中存有Microsoft Jet数据库引擎值的键数据库引擎值的键的有关信息。的有关信息。LoginTimeout:注册超时。在注册进入一个:注册超时。在注册进入一个ODBC数据库时,系统发出错误信号前等待的时数据库时,系统发出错误信号前等待的时间。缺省值为间。缺省值为20秒,如果设为零,系统将永久等秒,如果设为零,系统将永久等待待Version:DAO版本信息。用来返回正在使用的版本信息。用来返回正在使用的DAO的版本信息的版本信息DefaultType:Workspace对象的类型。设置或返回对象的类型。设置或返回一个值,该值为创建下一个工作区对象指出默认连一个值,该值为创建下一个工作区对象指出默认连接类型(工作区类型)。该属性的取值有两个:接类型(工作区类型)。该属性的取值有两个:DbUseJet表示创建连接到表示创建连接到Microsoft Jet数据库引擎数据库引擎的工作区对象,的工作区对象, DbUseODBC表示创建连接到数据表示创建连接到数据源的工作区对象。源的工作区对象。8.2 DAO8.2 DAO对象对象DBEngine对象的方法对象的方法CreateWorkspace:创建一个新的:创建一个新的Workspace对象。可以选用参数来设对象。可以选用参数来设置置Workspace的类型以及访问的用户的类型以及访问的用户名称和访问的口令。名称和访问的口令。CompactDatabase:压缩或转换一:压缩或转换一个关闭的个关闭的Microsoft Jet数据库。数据库。RegisterDatabase:将:将ODBC数据源数据源的连接信息注册到的连接信息注册到Windows。8.2 DAO8.2 DAO对象对象RepairDatabase:修复一个关闭的:修复一个关闭的Microsoft Jet数数据库。据库。Idle:挂起数据处理进程,使:挂起数据处理进程,使DBEngine处于空闲状处于空闲状态态8.2 DAO8.2 DAO对象对象CreateWorkspace方法用于创建一个具有指定类型、用户方法用于创建一个具有指定类型、用户名称和口令的名称和口令的Workspace对象。其语法如下:对象。其语法如下:Set Workspace对象变量对象变量=DBEngine.CreateWorkspace(name,user,password,type)CreateWorkspace的参数有的参数有name、user、password、type,说明如下。,说明如下。name:String类型,用于指明类型,用于指明Workspace的名称。的名称。user:String类型,用于指明访问的用户名称。类型,用于指明访问的用户名称。password:String类型,用于指定访问的口令。类型,用于指定访问的口令。type:常量,指明所建立的:常量,指明所建立的Workspace的类型,取值有两个,的类型,取值有两个,分别是分别是dbUseJet(创建(创建Microsoft Jet工作区)和工作区)和dbUseODBC(创建(创建ODBC工作区)。工作区)。8.2 DAO8.2 DAO对象对象Workspace对象Workspace对象的属性对象的属性Name:设置或返回用户定义的:设置或返回用户定义的Workspace对象对象的名称。的名称。Type:Workspace对象的类型。如果连接对象的类型。如果连接Microsoft Jet数据库,则为数据库,则为Microsoft Jet Workspace对象;如果连接对象;如果连接ODBC数据库,则为数据库,则为ODBC Workspace对象。对象。(3)UserName:拥有该:拥有该Workspace对象的用户对象的用户或用户组的名称。或用户组的名称。(4)LoginTimeout:在注册进入一个:在注册进入一个ODBC数数据库时,系统发出错误信号前等待的时间,缺省据库时,系统发出错误信号前等待的时间,缺省值为值为20秒。如果设为零,系统将永久等待。秒。如果设为零,系统将永久等待。8.2 DAO8.2 DAO对象对象图8.4 Workspace集合和对象8.2 DAO8.2 DAO对象对象Workspace对象的方法对象的方法CreateDatabase:在一个指定的工:在一个指定的工作区中建立一个新的作区中建立一个新的Jet数据库对象数据库对象(只能是(只能是.mdb,且存放在磁盘上),且存放在磁盘上),并把数据库对象作为函数值返回。并把数据库对象作为函数值返回。该方法只能创建该方法只能创建Jet数据库(只能是数据库(只能是.mdb,且存放在磁盘上),也是代,且存放在磁盘上),也是代码创建码创建Jet数据库的惟一方法。数据库的惟一方法。8.2 DAO8.2 DAO对象对象CreateGroup:在一个指定的工作区建立:在一个指定的工作区建立一个新的组一个新的组Group对象。对象。CreateUser:在一个指定的工作区建立一:在一个指定的工作区建立一个新的组个新的组User对象。对象。OpenConnection:在:在ODBC数据源上打数据源上打开一个开一个Connection对象(仅用于对象(仅用于ODBC Direct Workspace,它通过,它通过Microsoft Jet 数据引擎直接访问数据引擎直接访问ODBC数据源的数据源的Workspace) OpenDatabase:打开一个现在的数据库。:打开一个现在的数据库。可以打开可以打开Jet3.51支持的所有类型的数据库。支持的所有类型的数据库。8.2 DAO8.2 DAO对象对象BeginTrans:将该语句后到:将该语句后到CommitTrans语句前的一系列的数据操作作为一个事务语句前的一系列的数据操作作为一个事务来完成,以便于在需要的时候使用来完成,以便于在需要的时候使用Rollback方法回退这一系列数据操作。方法回退这一系列数据操作。CommitTrans:结束当前的事务并且将所:结束当前的事务并且将所进行的修改保存到数据库中。进行的修改保存到数据库中。Rollback:回退从:回退从BeginTrans开始到开始到CommitTrans提交的事务。提交的事务。Close:关闭该:关闭该Workspace对象以及它的任对象以及它的任何子对象,即将何子对象,即将Workspace对象从内存中删对象从内存中删除。除。8.2 DAO8.2 DAO对象对象 Database对象对象Databases集合指一系列集合指一系列的的Database对象,每个对象,每个Database对象映射一个对象映射一个打开的物理数据库。打开的物理数据库。 Database集合和对象的集合和对象的层次结构图如图层次结构图如图8.5所示。所示。其中,其中,TableDef对象为对象为Database对象子集的默对象子集的默认对象。认对象。图8.5 Database集合和对象8.2 DAO8.2 DAO对象对象Database对象的属性对象的属性Name:设置或返回数据库的完整路径和:设置或返回数据库的完整路径和文件名。文件名。Connect:设置或返回打开外部数据库时:设置或返回打开外部数据库时的连接字符串(的连接字符串(Connect string)。)。Connection:设置或返回:设置或返回ODBC连接属性,连接属性,包括用户名、口令等。包括用户名、口令等。Transactions:返回是否可以使用:返回是否可以使用BeginTrans、CommitTrans或或RollBack,实现批量写入,取消写入。实现批量写入,取消写入。8.2 DAO8.2 DAO对象对象QueryTimeout:设置当使用:设置当使用ODBC调调用打开客户服务器结构的数据库时,用打开客户服务器结构的数据库时,操作等待的时间。操作等待的时间。CollatingOrder:返回数据库中文排序:返回数据库中文排序方式。方式。Count:返回:返回Database对象的数量。对象的数量。RecordsAffected:返回执行:返回执行Execute命命令后,被操作的记录数。令后,被操作的记录数。Version:返回所打开数据库的版本号。:返回所打开数据库的版本号。8.2 DAO8.2 DAO对象对象Updatable:返回是否可对数据库进行写入或删除:返回是否可对数据库进行写入或删除数据操作。数据操作。Replicable:设置或返回数据库或数据库对象可以:设置或返回数据库或数据库对象可以被复制。被复制。V1xNullBehavior:设置是否将:设置是否将“Text”类型或类型或“Memo”类型的字段的空字符串转换为类型的字段的空字符串转换为Null,其值,其值为为True时,进行转换。时,进行转换。8.2 DAO8.2 DAO对象对象Database对象的方法对象的方法(1)OpenRecordset:打开:打开Recordset记录记录集对象。它是集对象。它是Database对象诸方法中使用对象诸方法中使用最多的一个方法。最多的一个方法。语法:语法:Set recordset = object.OpenRecordset (source, type, options, lockedits)参数参数source:字符串型,指定新建的:字符串型,指定新建的Recordset对象的记录源,可以是表名、查询名或一个返对象的记录源,可以是表名、查询名或一个返回若干记录的回若干记录的SQL语句,对于语句,对于Microsoft Jet数据库数据库中的表类型的中的表类型的Recordset对象,它只能是表名。对象,它只能是表名。8.2 DAO8.2 DAO对象对象参数参数type:可选,指定:可选,指定Recordset对象的类型,对象的类型,它可取表它可取表8.1中的值。中的值。参数参数options:可选,指定:可选,指定Recordset对象的其它对象的其它属性,它可取表属性,它可取表8.2中的值。中的值。参数参数lockedits:可选,指定:可选,指定Recordset对象的锁对象的锁定类型,它可取表定类型,它可取表8.3中的值。中的值。8.2 DAO8.2 DAO对象对象常量常量说明说明dbOpenTable打开表类型打开表类型Recordset对象(仅对对象(仅对Microsoft Jet workspace有效)有效)dbOpenDynamic打开动态(打开动态(Dynamic)类型)类型Recordset对象(仅对象(仅对对Microsoft Jet workspaces有效),类似有效),类似ODBC动态游标动态游标dbOpenDynaset打开动态集(打开动态集(dynaset)类型)类型Recordset对象对象dbOpenSnapshot打开一个快照(打开一个快照(Snapshot)类型)类型Recordset对象对象dbOpenForwardOnly 打开一个单向向前打开一个单向向前Recordset对象对象表8.1 Type参数的取值8.2 DAO8.2 DAO对象对象常量说明dbAppendOnly只允许追加新记录dbSQLPassThrough传递一个SQL语句dbSeeChanges当别的用户在编辑时,企图修改数据,会产生一个运行错误dbDenyWrite禁止写dbDenyRead禁止读dbForwardOnly只能向前(为了与以前版本兼容)dbReadOnly只能读dbRunAsync运行异步查询(只针对ODBC Direct Workspace有关)dbExecDirect跳过SQL Prepare直接调用SQL Exec Direct运行查询dbInconsistent允许不一致修改dbConsistent只允许一致性修改表8.2 Option参数的取值8.2 DAO8.2 DAO对象对象常量说明dbReadOnly只允许读dbPessimistic在多用户环境下,使用悲观锁定策略,即一旦使用Edit方法,将锁定编辑的页dbOptimistic在多用户环境下,使用乐观锁定策略,即直到使用Update方法时才锁定所编辑的页dbOptimisticValue用基于行的乐观一致性锁定策略(只针对ODBC Direct Workspace有效)dbOptimisticBatch使用批量乐观更新(只针对ODBC Direct Workspace有效)表8.3 lockedits参数的取值8.2 DAO8.2 DAO对象对象Close:关闭:关闭DAO对象。对象。CreateProperty:创建一个新的用户定义的:创建一个新的用户定义的Property对象,只对对象,只对Microsoft Jet Wordspace有有效。效。CreateQueryDef:创建一个新的查询定义:创建一个新的查询定义QueryDef对象。对象。CreateTableDef:创建一个新的表定义:创建一个新的表定义TableDef对象。对象。CreateRelation:创建一个新的联系:创建一个新的联系Relation对象,对象,只对只对Microsoft Jet Wordspace有效。有效。8.2 DAO8.2 DAO对象对象Execute:在一个指定的连接或数据库:在一个指定的连接或数据库对象上运行一个功能查询或执行一个对象上运行一个功能查询或执行一个SQL语句。语句。NewPassword:改变口令。:改变口令。MakeReplia:复制数据库,只对:复制数据库,只对Microsoft Jet Wordspace有效。有效。Synchronize:使两个复制同步,只对:使两个复制同步,只对Microsoft Jet Wordspace有效。有效。8.2 DAO8.2 DAO对象对象 TableDef对象对象TableDef集合和对象的层集合和对象的层次结构图如图次结构图如图9.6所所示。它包括字段示。它包括字段(Field)和索引)和索引(Index)两个对象。)两个对象。 图8.6 TableDef集合和对象8.2 DAO8.2 DAO对象对象TableDef对象的属性对象的属性Name:设置或返回:设置或返回TableDef对象的名称。对象的名称。可以和数据库中表的名称不一样。可以和数据库中表的名称不一样。Attributes:设置或返回:设置或返回TableDef对象的特对象的特性。如是否打开为打开为独占方式;该表性。如是否打开为打开为独占方式;该表是否是由是否是由Jet数据库引擎提供的系统表等等。数据库引擎提供的系统表等等。ConflictTable:冲突表的名字,该表包含:冲突表的名字,该表包含了两个副本在同步期间相互冲突的数据库了两个副本在同步期间相互冲突的数据库记录。记录。8.2 DAO8.2 DAO对象对象DataCreated:返回创建表的日期和时:返回创建表的日期和时间。是日期变量型。间。是日期变量型。LastUpdated:返回最近一次修改表的。:返回最近一次修改表的。日期和时间。是日期变量型。日期和时间。是日期变量型。RecordCount:TableDef对象中所有的对象中所有的记录总数。对于基表(记录总数。对于基表(Base Table),),RecordCount属性返回的是表中的记录属性返回的是表中的记录总数;对于链接表(总数;对于链接表(Linked Table),),返回的是返回的是-1。8.2 DAO8.2 DAO对象对象Updatable:指定能否对表中的数据进行修改。:指定能否对表中的数据进行修改。取取True或或False值。对于新建的值。对于新建的TableDef对象,对象,该属性值为该属性值为True。但在有些场合,如网络环。但在有些场合,如网络环境,表可以被锁定,或用户以只读方式打开境,表可以被锁定,或用户以只读方式打开时,该值为时,该值为False,表明不能对表更新。,表明不能对表更新。ValidationRule:有效性规则,在一个字段:有效性规则,在一个字段被修改或添加到一个表时,设置或返回用被修改或添加到一个表时,设置或返回用来使该字段中数据生效的值。字符串类型。来使该字段中数据生效的值。字符串类型。ValidationText:在键入到某个字段对象中:在键入到某个字段对象中的值不满足有效性规则时,应用程序所显的值不满足有效性规则时,应用程序所显示的提示性信息。示的提示性信息。8.2 DAO8.2 DAO对象对象TableDef对象的方法对象的方法CreateField:在:在TableDef对象中建立一个新的字对象中建立一个新的字段,并创建一个段,并创建一个Field对象,建立对该字段的引对象,建立对该字段的引用。用。CreateIndex:在:在TableDef对象中建立一个新索对象中建立一个新索引,并创建一个引,并创建一个Index对象,建立对该索引的引对象,建立对该索引的引用。用。CreateProperty:建立一个用户自定义的属性,:建立一个用户自定义的属性,并创建一个并创建一个Property对象,建立对该属性的引用。对象,建立对该属性的引用。OpenRecordset:创建一个记录集对象,显示一:创建一个记录集对象,显示一个或多个表中部分或全部的字段的数据。个或多个表中部分或全部的字段的数据。RefreshLink:更新与链接表的链接。:更新与链接表的链接。8.2 DAO8.2 DAO对象对象Recordset对象对象在使用在使用DAO访问数据访问数据库时,一般都使用库时,一般都使用Recordset对象来操对象来操作记录,如增加记录、作记录,如增加记录、删除记录、更新数据删除记录、更新数据库、在记录中移动等。库、在记录中移动等。Recordset对象的层次对象的层次结构如图结构如图8.7所示。所示。图8.7 Recordset对象与集合8.2 DAO8.2 DAO对象对象Recordset对象共有对象共有5种类型。种类型。Table:是缺省类型。此类型的:是缺省类型。此类型的Recordset对象是物对象是物理表的映射。它包含单一表对象的所有数据。它可理表的映射。它包含单一表对象的所有数据。它可以对数据进行完全访问,如添加、修改、删除记录。以对数据进行完全访问,如添加、修改、删除记录。Dynast:此类型的:此类型的Recordset对象是单一表对象或对象是单一表对象或Select类型查询结果的映射。它所包含的字段一般类型查询结果的映射。它所包含的字段一般来源于多个表,是一个动态的记录集合。它可以有来源于多个表,是一个动态的记录集合。它可以有Table类型所有编辑功能,但不能使用索引。类型所有编辑功能,但不能使用索引。Snapshot:此类型的:此类型的Recordset对象包含一组不能对象包含一组不能更改的记录集合,是只读的。用来浏览数据和生更改的记录集合,是只读的。用来浏览数据和生成报表。成报表。8.2 DAO8.2 DAO对象对象(4)ForwardOnly:此类型的:此类型的Recordset对象和对象和Snapshot类型一样,但只能在记录类型一样,但只能在记录集合中向前移动,用于网络数据库环境。集合中向前移动,用于网络数据库环境。(5)Dynamic:此类型的:此类型的Recordset对对象是一个查询结果的记录集合。可以象是一个查询结果的记录集合。可以进行增加、修改、删除等操作。并且进行增加、修改、删除等操作。并且在多用户环境,其他用户对对象记录在多用户环境,其他用户对对象记录来源表中的数据的修改也会反映到该来源表中的数据的修改也会反映到该Recordset对象上。对象上。8.2 DAO8.2 DAO对象对象Recordset对象的属性对象的属性AbsolutePosition:设置或读取当前记:设置或读取当前记录在记录集中的位置。录在记录集中的位置。BOF:返回值表明指针是否已到记录:返回值表明指针是否已到记录集中第一条记录之前。一般在记录间集中第一条记录之前。一般在记录间向前移动记录指针时,应先检查此属向前移动记录指针时,应先检查此属性以保证指针不会移出记录集。性以保证指针不会移出记录集。Bookmark:指向特定记录的标签。:指向特定记录的标签。Bookmarkable:返回值表明此:返回值表明此Recordset对象是否支持对象是否支持Bookmark。8.2 DAO8.2 DAO对象对象EditMode:返回一个表明当前记录的编辑状:返回一个表明当前记录的编辑状态的值。态的值。EOF:返回值表明指针是否已到记录集中最:返回值表明指针是否已到记录集中最后一条记录之后。一般在记录间向后移动记后一条记录之后。一般在记录间向后移动记录指针时,应先检查此属性以保证指针不会录指针时,应先检查此属性以保证指针不会移出记录集。移出记录集。Filter:过滤记录的字符串,相当于去掉:过滤记录的字符串,相当于去掉SQL语句中语句中WHERE关键字的关键字的WHERE子句。子句。Index:设置或返回一个值表明:设置或返回一个值表明Recordset对对象记录显示顺序的索引的名称。象记录显示顺序的索引的名称。LastModified:返回一个指向:返回一个指向Table对象中对象中最近修改过的记录的标签。最近修改过的记录的标签。8.2 DAO8.2 DAO对象对象LastUpdated:最后一次将:最后一次将Recordset的改的改变更新到数据库的日期和时间。变更新到数据库的日期和时间。LockEdits:取值为:取值为True或或False。该值取。该值取True时,锁定当前正在更新的页面;该值时,锁定当前正在更新的页面;该值取取False时,仅当时,仅当Update方法用于编辑的方法用于编辑的表时锁定页面。表时锁定页面。Name:Recordset对象的名称。对象的名称。NoMatch:取值为:取值为True或或False。当用。当用Seek或或Find方法查找记录时,如果没有满方法查找记录时,如果没有满足给定条件的记录,该值取足给定条件的记录,该值取True。PercentPosition:当前记录指针的位置与:当前记录指针的位置与记录总数的百分比。记录总数的百分比。8.2 DAO8.2 DAO对象对象RecordCount:Recordset对象中记录的总对象中记录的总数。数。Restartable:Recordset对象是否支持对象是否支持Requery方法。方法。Sort:指定:指定Recordset对象显示的排序准则,对象显示的排序准则,相当于去掉相当于去掉SQL语句中语句中ORDER BY关键字关键字的的ORDER BY子句。子句。Transactions:是否支持事务处理的回退功:是否支持事务处理的回退功能。能。ValidationRule:在一个字段被修改或添加:在一个字段被修改或添加到一个表中时,返回或设置用来使该字段到一个表中时,返回或设置用来使该字段中数据生效的值。是一个中数据生效的值。是一个String类型的字符类型的字符串。串。8.2 DAO8.2 DAO对象对象ValidationText:在键入到某个字段对象中的值:在键入到某个字段对象中的值不满足有效性规则时,应用程序所显示的提示性不满足有效性规则时,应用程序所显示的提示性信息。信息。2Recordset对象的方法对象的方法AddNew:向:向Recordset对象添加一条新记录,对象添加一条新记录,并将记录指针移到该记录。并将记录指针移到该记录。CancelUpdate:取消尚未执行的数据更新操作。:取消尚未执行的数据更新操作。Clone:创建原始:创建原始Recordset对象的一个副本。对象的一个副本。Close:关闭当前:关闭当前Recordset对象。对象。8.2 DAO8.2 DAO对象对象CopyQueryDef:建立:建立Recordset对象所基于的对象所基于的QueryDef的拷贝。的拷贝。Delete:在可更新的:在可更新的Recordset对象中删除当前记对象中删除当前记录。录。Edit:把一个可更新的:把一个可更新的Recordset对象的当前记录对象的当前记录拷贝到拷贝缓冲区(拷贝到拷贝缓冲区(Copy Buffer),以便于编),以便于编辑,即设置为编辑状态。一般和辑,即设置为编辑状态。一般和Update方法配合方法配合使用。先将使用。先将Recordset对象设为编辑状态,然后对象设为编辑状态,然后对数据进行修改,最后用对数据进行修改,最后用Update方法将修改更新方法将修改更新到数据库中到数据库中FindFirst、FindLast、FindPrevious、FindNext:按:按Recordset对象的索引和排序顺序,查找满对象的索引和排序顺序,查找满足约束条件的第一条记录、最后一条记录、上一足约束条件的第一条记录、最后一条记录、上一条记录、下一条记录。条记录、下一条记录。8.2 DAO8.2 DAO对象对象Move:将记录指针移动到指定位置。:将记录指针移动到指定位置。MoveFirst、MoveLast、MovePrevious、 MoveNext:移动到指定:移动到指定 Recordset 对象对象中的第一个、最后一个、上一个或下一个中的第一个、最后一个、上一个或下一个记录并使该记录成为当前记录。记录并使该记录成为当前记录。OpenRecordset:创建一个新的:创建一个新的Recordset对象,并将它添加到对象,并将它添加到Recordsets集合中。集合中。Requery:通过重新执行:通过重新执行Recordset对象所对象所基于的查询更新该基于的查询更新该Recordset对象的数据。对象的数据。8.2 DAO8.2 DAO对象对象Seek:按:按Recordset对象的索引和排对象的索引和排序顺序,将记录指针移动到满足约序顺序,将记录指针移动到满足约束条件的第一条记录。束条件的第一条记录。Update:进入编辑方式后,必须要:进入编辑方式后,必须要使用使用Update才能确定写入数据,写才能确定写入数据,写入后退出编辑方式。入后退出编辑方式。8.2 DAO8.2 DAO对象对象QueryDef对象对象QueryDef对象是对象是Microsoft Jet数据库中一个查询的存储定数据库中一个查询的存储定义(义(stored definition)或)或ODBC direct workspace中一中一个查询的临时定义个查询的临时定义(temporary definition)。)。它是数据库的永久性对象,它是数据库的永久性对象,存放在磁盘文件中。存放在磁盘文件中。图8.8 QueryDef对象的层次结构图8.2 DAO8.2 DAO对象对象QueryDef对象的属性对象的属性LastUpdated:最后一次将:最后一次将QueryDef的的改变更新到数据库的日期和时间。改变更新到数据库的日期和时间。Name:QueryDef对象的名称。它可以对象的名称。它可以和数据库中查询的名称不一致。和数据库中查询的名称不一致。RecordsAffected:受最近调用的方法影:受最近调用的方法影响的记录数。响的记录数。Replicable:设置或返回一个值决定:设置或返回一个值决定QueryDef对象是否可以复制。对象是否可以复制。8.2 DAO8.2 DAO对象对象SQL:定义查询的:定义查询的SQL语句。可以通过修语句。可以通过修改改SQL语句更改查询。如,可以通过修改语句更改查询。如,可以通过修改SQL中中WHERE子句改变约束条件,再进子句改变约束条件,再进行查询。行查询。Type:设置或返回一个值表明:设置或返回一个值表明QueryDef对象的类型。对象的类型。Updatable:返回一个值表明:返回一个值表明QueryDef对对象是否可以更新。象是否可以更新。8.2 DAO8.2 DAO对象对象QueryDef对象的方法对象的方法Close:关闭一个打开的:关闭一个打开的QueryDef对象。对象。CreateProperty:为:为QueryDef对象创建对象创建一个用户定义的属性。一个用户定义的属性。Execute:运行一个动作查询或执行一个:运行一个动作查询或执行一个SQL语句。语句。OpenRecordset:创建一个新的:创建一个新的Recordset对象并将它添加到对象并将它添加到Recordsets集合中。集合中。8.2 DAO8.2 DAO对象对象图8.9 Field集合和对象8.2 DAO8.2 DAO对象对象 Field对象对象Field对象的属性对象的属性AllowZeroLength:设置或返回一个值表明:设置或返回一个值表明零长度的字符串对于某零长度的字符串对于某Field对象的对象的Value属属性是否有效。可取性是否有效。可取True或或False值。值。Attributes:设置或返回一个值表明:设置或返回一个值表明Field对对象的一个或多个特性。象的一个或多个特性。CollatingOrder:返回一个值说明用于字符:返回一个值说明用于字符串比较或排序的文本顺序。串比较或排序的文本顺序。DataUpdatable:返回一个值表明:返回一个值表明Field对象对象里的数据是否可以更新。里的数据是否可以更新。8.2 DAO8.2 DAO对象对象DefaultValue:设置或返回一个:设置或返回一个Field对象对象缺省值。缺省值。Name:用户定义的:用户定义的Field对象名称。对象名称。OrdinalPosition:Fields集合中集合中Field对象对象的相对位置。的相对位置。Required:Field对象是否要求非空值。对象是否要求非空值。Size:用字节表示的:用字节表示的Field对象的最大值。对象的最大值。SourceTable:Field对象数据来源的原始对象数据来源的原始表名。表名。8.2 DAO8.2 DAO对象对象Type:Field对象的数据类型。对象的数据类型。ValidateOnSet:当:当Field对象的对象的Value属性属性设置时,该设置时,该Field对象的值是否立即有效。对象的值是否立即有效。ValidationRule:在一个字段被修改或添:在一个字段被修改或添加到一个表中时,返回或设置用来使该字加到一个表中时,返回或设置用来使该字段中数据生效的值。段中数据生效的值。ValidationText:在键入到某个字段对象:在键入到某个字段对象中的值不满足有效性规则时,应用程序中的值不满足有效性规则时,应用程序所显示的提示性信息。所显示的提示性信息。Value:以:以Type属性指定的数据类型赋属性指定的数据类型赋给给Field对象的值。对象的值。8.2 DAO8.2 DAO对象对象Field对象的方法对象的方法AppendChunk:给:给OLE对象或备对象或备注(注(memo)Field对象添加一个字对象添加一个字符串。符串。CreateProperty:为:为Field对象创建对象创建一个新的用户定义的属性。一个新的用户定义的属性。GetChunk:一个:一个Recordset对象中对象中的的Fields集合中的备注对象或集合中的备注对象或OLE对象中的一部分或全部内容。对象中的一部分或全部内容。8.3 DAO8.3 DAO编程实例编程实例本节通过对本节通过对TuiMag.mdb数据库数据库StuInfo表的访问实例,表的访问实例,来讲解来讲解DAO访问数据库的一般步骤:访问数据库的一般步骤:(1)在集成开发环境中,新建一个工程,将工程的命)在集成开发环境中,新建一个工程,将工程的命名为名为DAOexample,并以,并以DAOexample.vbp保存。保存。(2)在)在Form1窗体上,按图窗体上,按图8.10所示添加所示添加8个标签控件,个标签控件,将它们的将它们的Caption属性分别设置为:学号、姓名、出属性分别设置为:学号、姓名、出生日期、所在班级、来源、联系电话、备注,并左生日期、所在班级、来源、联系电话、备注,并左对齐,垂直方向相同间距;再添加对齐,垂直方向相同间距;再添加1个文本框,并命个文本框,并命名为名为txtFd,然后复制该文本框并粘贴为控件数组,然后复制该文本框并粘贴为控件数组,共生成文本框共生成文本框8个,分别对应于学号、姓名、出生日个,分别对应于学号、姓名、出生日期、所在班级、来源、联系电话、备注。期、所在班级、来源、联系电话、备注。8.3 DAO8.3 DAO编程实例编程实例图8.10 Form1窗体及其上的控件(3)在窗体上创建简单菜)在窗体上创建简单菜单:单:“文件文件”(菜单名为(菜单名为mnuFile),它有一个菜单),它有一个菜单项项“退出退出”(菜单项名为(菜单项名为mnuExit););“数据数据”(菜(菜单名为单名为mnuData),它也只),它也只有一个菜单项有一个菜单项“保存记录保存记录”(菜单项名为(菜单项名为mnuDataSave)。)。8.3 DAO8.3 DAO编程实例编程实例(4)为工程添加一个类模块,命名为)为工程添加一个类模块,命名为cStudent,并以,并以cStudent.cls为名保存。为名保存。(5)将下面的代码添到)将下面的代码添到cStudent模块的声明段。模块的声明段。Option ExplicitPrivate mdb As DatabasePrivate mrs As RecordsetPrivate mblnIsDirty As BooleanPrivate mrsStuID, mrsStuName, mrsStuSex, mrsStuClass, mrsStuFrom, mrsStuTel As StringPrivate mrsStuBirthDate As Date8.3 DAO8.3 DAO编程实例编程实例定义定义Move方法的常数方法的常数Public Enum rsMove FirstRecord = 1 LastRecord = 2 NextRecord = 3 PreviousRecord = 4End Enum定义定义Error常数常数Public Enum mError ErrInvalidMoveType = vbObjectError + 1000 + 11 ErrNoRecords = vbObjectError + 1000 + 12End Enum8.3 DAO8.3 DAO编程实例编程实例(6)将下列代码添加到)将下列代码添加到cStudent模块中的模块中的Class_Initialize事件和事件和 Class_Terminate 事件过程中。事件过程中。Private Sub Class_Initialize()打开指定的数据库打开指定的数据库Dim strDBName As StringSet mdb = DBEngine.Workspaces(0).OpenDatabase(n:TuiMag97.mdb)打开记录集对象打开记录集对象Set mrs = mdb.OpenRecordset(StuInfo, dbOpenDynaset, dbSeeChanges, dbOptimistic)如果记录集中没有记录,提示错误信息如果记录集中没有记录,提示错误信息If mrs.BOF Then RaiseClassError ErrNoRecordsEnd If8.3 DAO8.3 DAO编程实例编程实例取首记录取首记录GetCurrentRecordEnd SubPrivate Sub Class_Terminate()关闭记录集对象并释放相应的资源关闭记录集对象并释放相应的资源mrs.CloseSet mrs = Nothing关闭数据库对象并释放相应的资源关闭数据库对象并释放相应的资源mdb.CloseSet mdb = NothingEnd Sub上述代码中,上述代码中,Class_Initialize事件用于打开数据库和创建一个事件用于打开数据库和创建一个Recordset对象,对象, Class_Terminate事件用于事件用于Class_Initialize关闭事关闭事件打开的变量。件打开的变量。8.3 DAO8.3 DAO编程实例编程实例(7)在)在cStudent模块中添加一个私有的模块中添加一个私有的RaiseClassError方法,该方方法,该方法用于显示由类模块触发的错误的描述和资源属性。法用于显示由类模块触发的错误的描述和资源属性。Private Sub RaiseClassError(lngErrorNumber As mError) Dim strDescription As String Dim strSource As String 描述错误原因描述错误原因 Select Case lngErrorNumber Case ErrInvalidMoveType strDescription = 非法移动操作!非法移动操作! Case ErrNoRecords strDescription = 表中没有记录!表中没有记录! Case Else strDescription = 无法确定的错误!无法确定的错误! End Select 8.3 DAO8.3 DAO编程实例编程实例创建错误产生的资源属性创建错误产生的资源属性 strSource = App.EXEName & .Class1 显示错误信息显示错误信息 Err.Raise lngErrorNumber, strSource, strDescriptionEnd Sub(8)在)在cStudent模块中添加一个模块中添加一个 GetCurrentRecord方法,方法,该方法用于从该方法用于从Recordset对象中取得数据并且将这些数对象中取得数据并且将这些数据赋值组模块级私有变量,以供据赋值组模块级私有变量,以供Property过程使用。过程使用。Private Sub GetCurrentRecord() 8.3 DAO8.3 DAO编程实例编程实例取得记录集中当前记录中各个字段值取得记录集中当前记录中各个字段值 mrsStuID = mrs!StuID mrsStuName = mrs!StuName mrsStuSex = mrs!StuSex mrsStuBirthDate = mrs!StuBirthDate mrsStuClass = mrs!StuClass mrsStuFrom = mrs!StuFrom mrsStuTel = mrs!StuTelEnd Sub 8.3 DAO8.3 DAO编程实例编程实例(9)在)在cStudent模块中添加一个私有的模块中添加一个私有的UpdateRecord事件过程,用于将模块级私有变量的值写到事件过程,用于将模块级私有变量的值写到Recordset对象对象中。中。Private Sub UpdateRecord()DAO编辑编辑/修改修改On Error GoTo ProcError开始编辑开始编辑 mrs.Edit mrs!StuID = mrsStuID mrs!StuName = mrsStuName mrs!StuSex = mrsStuSex mrs!StuBirthDate = mrsStuBirthDate mrs!StuClass = mrsStuClass mrs!StuFrom = mrsStuFrom mrs!StuTel = mrsStuTel 提交修改提交修改 mrs.Update 清除标记清除标记 mblnIsDirty = False Exit SubProcError:清除使用清除使用Edit方法所作的修改方法所作的修改 mrs.MovePrevious mrs.MoveNext Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContextEnd Sub8.3 DAO8.3 DAO编程实例编程实例(10)在类模块中添加有关)在类模块中添加有关mStuID、mStuName、mStuSex、mStuBirthDate、mStuClass、mStuFrom和和mStuTel共共7个模块级变量的个模块级变量的Property Get过程和过程和Property Let过程。过程。Public Property Get mStuID() As String mStuID = mrsStuIDEnd PropertyPublic Property Let mStuID(strStuID As String) mrsStuID = strStuID 设置设置mblnIsDirty标记标记 mblnIsDirty = TrueEnd PropertyPublic Property Get mStuName() As String mStuName = mrsStuNameEnd PropertyPublic Property Let mStuName(strStuName As String) mrsStuName = strStuName 设置设置mblnIsDirty标记标记 mblnIsDirty = TrueEnd Property8.3 DAO8.3 DAO编程实例编程实例Public Property Get mStuSex() As String mStuSex = mrsStuSexEnd PropertyPublic Property Let mStuSex(strStuSex As String) mrsStuSex = strStuSex 设置设置mblnIsDirty标记标记 mblnIsDirty = TrueEnd PropertyPublic Property Get mStuBirthDate() As String mStuBirthDate = mrsStuBirthDateEnd PropertyPublic Property Let mStuBirthDate(strStuBirthDate As String) mrsStuBirthDate = strStuBirthDate 设置设置mblnIsDirty标记标记 mblnIsDirty = TrueEnd PropertyPublic Property Get mStuClass() As String mStuClass = mrsStuClassEnd Property8.3 DAO8.3 DAO编程实例编程实例Public Property Let mStuClass(strStuClass As String) mrsStuClass = strStuClass 设置设置mblnIsDirty标记标记 mblnIsDirty = TrueEnd PropertyPublic Property Get mStuFrom() As String mStuFrom = mrsStuFromEnd PropertyPublic Property Let mStuFrom(strStuFrom As String) mrsStuFrom = strStuFrom 设置设置mblnIsDirty标记标记 mblnIsDirty = TrueEnd PropertyPublic Property Get mStuTel() As String mStuTel = mrsStuTelEnd PropertyPublic Property Let mStuTel(strStuTel As String) mrsStuTel = strStuTel 8.3 DAO8.3 DAO编程实例编程实例设置设置mblnIsDirty标记标记 mblnIsDirty = TrueEnd Property上述代码中,上述代码中,Property Get过程用于对模块级变量赋新值并重新设置修改标记,过程用于对模块级变量赋新值并重新设置修改标记,Property Let过程用于取得模块级变量的值。过程用于取得模块级变量的值。8.3 DAO8.3 DAO编程实例编程实例(11)在类模块中添加)在类模块中添加IsDirty变量的变量的Property Get事件过程,它用于返回当前事件过程,它用于返回当前mblnIsDirty标记的值。标记的值。Public Property Get IsDirty() As Boolean 取得标记值取得标记值 IsDirty = mblnIsDirtyEnd Property(12)在类模块中添加)在类模块中添加Move方法,用于根据方法,用于根据lngMoveType参数移动记录指针,其中参数移动记录指针,其中lngMoveType参数的值由类模块语句声明部分的结构决定。参数的值由类模块语句声明部分的结构决定。Public Sub Move(lngMoveType As rsMove)移动并刷新属性值移动并刷新属性值Select Case lngMoveType Case FirstRecord mrs.MoveFirst Case LastRecord mrs.MoveLast Case NextRecord mrs.MoveNext 8.3 DAO8.3 DAO编程实例编程实例如果如果EOF属性值为真,移至最后一条记录属性值为真,移至最后一条记录 If mrs.EOF Then mrs.MoveLast Case PreviousRecord 如果如果BOF属性值为真,移至第一条记录属性值为真,移至第一条记录 mrs.MovePrevious If mrs.BOF Then mrs.MoveFirst Case Else 参数不对,显示出错信息参数不对,显示出错信息 RaiseClassError ErrInvalidMoveTypeEnd SelectGetCurrentRecordEnd Sub8.3 DAO8.3 DAO编程实例编程实例(13)在类模块中添加)在类模块中添加SaveRecord方法,用于测试方法,用于测试mblnIsDirty标记的值以及判断是标记的值以及判断是否需要更新当前记录。否需要更新当前记录。Public Sub SaveRecord()保存当前修改保存当前修改测试标志测试标志If mblnIsDirty Then 更新当前记录的值更新当前记录的值 UpdateRecordElse 不需要更新记录不需要更新记录End IfEnd Sub8.3 DAO8.3 DAO编程实例编程实例(14)在窗体)在窗体frmDAOexample的声明部分添加如下代码,用于创建一个的声明部分添加如下代码,用于创建一个cStudent类型类型的变量,另外还定义一些控件数据的常数和状态标志常数。的变量,另外还定义一些控件数据的常数和状态标志常数。Option ExplicitPrivate mStudent As cStudent定义四个命令按钮的常数定义四个命令按钮的常数Const cmdMoveFirst = 0Const cmdMovePrevious = 1Const cmdMoveNext = 2Const cmdMoveLast = 3定义窗体中文本框的索引常数定义窗体中文本框的索引常数Const txtStuID = 0Const txtStuName = 1Const txtStuSex = 2Const txtStuBirthDate = 3Const txtStuClass = 4Const txtStuFrom = 5Const txtStuTel = 6Const txtStuMem = 7刷新标记刷新标记Private mblnInRefresh As Boolean 8.3 DAO8.3 DAO编程实例编程实例(15)在窗体)在窗体frmDAOexample的的Form_Load事件过程添加如下代码,用于创建一个事件过程添加如下代码,用于创建一个cStudent类对象和装载第一条记录,并含有出现处理程序段,如果出现错误的话,类对象和装载第一条记录,并含有出现处理程序段,如果出现错误的话,显示错误信息并终止应用程序的运行。显示错误信息并终止应用程序的运行。Private Sub Form_Load() 创建创建cStudent对象并且显示首记录的数据对象并且显示首记录的数据 On Error GoTo ProcError Dim strDBName As String Screen.MousePointer = vbHourglass 创建创建mStudent对象对象 Set mStudent = New cStudent 显示首记录的数据显示首记录的数据 GetDataProcExit: Screen.MousePointer = vbDefault Exit SubProcError: 如果出错的话,显示出错信息如果出错的话,显示出错信息 MsgBox Err.Description Unload Me Resume ProcExitEnd Sub8.3 DAO8.3 DAO编程实例编程实例(16)在窗体)在窗体frmDAOexample的的Form_ QueryUnload事件过程添加如下代码,用于事件过程添加如下代码,用于在卸载窗体时保存当前记录的数据,如果出现错误的话,提示用户是否继续运行在卸载窗体时保存当前记录的数据,如果出现错误的话,提示用户是否继续运行应用程序。应用程序。Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)On Error GoTo ProcErrorScreen.MousePointer = vbHourglass保存当前记录保存当前记录mStudent.SaveRecordProcExit:Screen.MousePointer = vbDefaultExit SubProcError:出现错误,无法保存记录,提示用户是否继续执行应用程序出现错误,无法保存记录,提示用户是否继续执行应用程序Dim strMsg As StringstrMsg = 保存过程出现如下错误:保存过程出现如下错误:strMsg = strMsg & vbCrLf & Err.Description & vbCrLfstrMsg = strMsg & 如果继续进行操作,修改的数据将丢失!如果继续进行操作,修改的数据将丢失! & vbCrLf8.3 DAO8.3 DAO编程实例编程实例strMsg = strMsg & 是否继续执行应用程序?是否继续执行应用程序?If MsgBox(strMsg, vbQuestion Or vbYesNo Or vbDefaultButton2) = vbNo Then Cancel = TrueEnd IfResume ProExitEnd Sub8.3 DAO8.3 DAO编程实例编程实例(17)在窗体)在窗体frmDAOexample的的cmdMove_Click事件过程中添加如下代码,用于保事件过程中添加如下代码,用于保存当前的记录,并且根据存当前的记录,并且根据mStudent对象的索引移动记录指针,然后刷新窗体。对象的索引移动记录指针,然后刷新窗体。Private Sub cmdMove_Click(Index As Integer)On Error GoTo ProcErrorScreen.MousePointer = vbHourglass保存当前记录保存当前记录mStudent.SaveRecord根据索引参数移动当前记录指针根据索引参数移动当前记录指针Select Case Index Case cmdMoveFirst mStudent.Move FirstRecord Case cmdMoveLast mStudent.Move LastRecord Case cmdMoveNext mStudent.Move NextRecord Case cmdMovePrevious mStudent.Move PreviousRecordEnd Select8.3 DAO8.3 DAO编程实例编程实例刷新窗体上的数据记录刷新窗体上的数据记录GetDataProcExit: Screen.MousePointer = vbDefault Exit SubProcError: 如果出错的话,显示出错信息如果出错的话,显示出错信息 MsgBox Err.Description, vbExclamation Unload Me Resume ProcExitEnd Sub8.3 DAO8.3 DAO编程实例编程实例(18)在窗体)在窗体frmDAOexample的的txtFd_Change事件过程中添加如下代码,事件过程中添加如下代码,用于将控件上的值赋给该对象的属性。其中用于将控件上的值赋给该对象的属性。其中mblnInRefresh标志用于指示标志用于指示当前的窗体是否已经被刷新,如果已经刷新,则无需再对当前的窗体是否已经被刷新,如果已经刷新,则无需再对mStudent对象对象的属性进行赋值。的属性进行赋值。Private Sub txtFd_Change(Index As Integer)如果需要的话,更新对象的属性如果需要的话,更新对象的属性On Error GoTo ProcErrorDim strValue As StringScreen.MousePointer = vbHourglass从控件中取得具体的值从控件中取得具体的值strValue = txtFd(Index).TextIf Not mblnInRefresh Then 更新类的属性更新类的属性 Select Case Index Case txtStuID mStudent.mStuID = strValue 8.3 DAO8.3 DAO编程实例编程实例Case txtStuName mStudent.mStuName = strValue Case txtStuSex mStudent.mStuSex = strValue Case txtStuBirthDate mStudent.mStuBirthDate = strValue Case txtStuClass mStudent.mStuClass = strValue Case txtStuFrom mStudent.mStuFrom = strValue Case txtStuTel mStudent.mStuTel = strValue End SelectEnd IfProcExit: Screen.MousePointer = vbDefault Exit Sub 8.3 DAO8.3 DAO编程实例编程实例ProcError: MsgBox Err.Description, vbExclamation Resume NextEnd Sub8.3 DAO8.3 DAO编程实例编程实例(19)在窗体)在窗体frmDAOexample菜单的菜单的mnuExit_Click事件过程中添加如下代码,用于事件过程中添加如下代码,用于卸载窗体。卸载窗体。Private Sub mnuExit_Click()Unload MeEnd Sub(20)在窗体)在窗体frmDAOexample菜单的菜单的mnuDataSave _Click事件过程中添加如下代码,事件过程中添加如下代码,用于保存当前记录的修改。用于保存当前记录的修改。Private Sub mnuDataSave_Click()On Error GoTo ProcErrorScreen.MousePointer = vbHourglass保存当前记录保存当前记录mStudent.SaveRecord刷新数据刷新数据GetDataProExit:Screen.MousePointer = vbDefaultExit SubProcError:Resume ProExitEnd Sub8.3 DAO8.3 DAO编程实例编程实例(21)在窗体)在窗体frmDAOexample中添加中添加GetData事件过程,主要用于根据事件过程,主要用于根据mStudent对象的属性来刷新控件并且设置标记的值,以免在对象的属性来刷新控件并且设置标记的值,以免在txt_Change过程过程中重复更新记录数据。中重复更新记录数据。Private Sub GetData() 显示当前数据显示当前数据设置设置mblnInRefresh标志位,以免标志位,以免txtFd_Change事件重复更新对象的属性值事件重复更新对象的属性值mblnInRefresh = True将属性值显示在控件中将属性值显示在控件中txtFd(txtStuID).Text = mStudent.mStuIDtxtFd(txtStuName).Text = mStudent.mStuNametxtFd(txtStuSex).Text = mStudent.mStuSextxtFd(txtStuBirthDate).Text = mStudent.mStuBirthDatetxtFd(txtStuClass).Text = mStudent.mStuClasstxtFd(txtStuFrom).Text = mStudent.mStuFromtxtFd(txtStuTel).Text = mStudent.mStuTel清除刷新标记清除刷新标记mblnInRefresh = FalseEnd Sub8.3 DAO8.3 DAO编程实例编程实例图8.11运行应用程序中的窗体
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号