第6章MFC ODBC编程 为了简化开发人员编写数据库应用程序,VC++的在其基础类库(MFC)里对ODBC API 进行了封装,实现了一个面向对象的数据库编程接口,使VC+的数据库变得更加容易。 本章首先对MFC ODBC的概貌进行简要介绍,然后讲述利用MFC ODBC进行数据库 开发的技巧,最后将通过具体数据库开发实例,详细讲述通过MFC ODBC开发数据库应 用程序的方法和过程。 6.1了解MFC ODBC MFC是Microsoft Foundation Class(微软基础类库)的缩写,它的设计目标是简化开 发人员的工作。MFC使开发人员创建基于Windows的应用程序,而不必掌握下层的 Windows体系结构。由于数据库应用程序是管理数据的重要方面,Microsoft开发了ODBC API的封装程序,为ODBC编程提供了一个面向对象的方法。 MFC对ODBC的封装主要是开发了CDatabase类和CRecordSet类。 6.1.1 CDatabase类 CDatabase类用于应用程序建立同数据源的连接。CDatabase类包含一个m hdbc变量, 它代表了数据源的连接句柄。如果要建立CDatabase类的实例,应先调用该类的构造函数, 再调用Open函数,通过调用,初始化环境变量,并执行与数据源的连接。关闭数据源连 接的函数是Close。. CDatabase类提供了对数据库进行操作的函数,为了执行事务操作,CDatabase类提供 了BeginTrans函数,当全部数据都处理完成后,可以通过调用CommitTrans函数提交事务, 或者在特殊情况下通过调用Rollback函数将处理回退。 CDatabase类提供的函数可以用于返回数据源的特定信息,例如通过GetConnect函数 返回在使用函数Open连接数据源时的连接字符串,通过调用IsOpen函数返回当前的 CDatabase实例是否己经连接到数据源上,通过调用CanUpdate函数返回当前的CDatabase 实例是否是可更新的,通过调用CanTransact函数返回当前的CDatabase实例是否支持事务 操作,等等。 总之,CDatabase类为C++数据库开发人员提供了ODBC的面向对象的编程接口。 6.1.2 CRecordSet类 要实现对结果集的数据操作,就要用到CRecordSet类。CRecordSet类定义了从数据库 接收或者发送数据到数据库的成员变量,CRecordSet类定义的记录集可以是表的所有列, 也可以是其中的一列,这是由$QL语句决定的。 CRecordSet类的成员变量m hstmt代表了定义该记录集的SQL语句句柄,m nFields
第 6 章 MFC ODBC 编程 为了简化开发人员编写数据库应用程序,VC++的在其基础类库(MFC)里对 ODBC API 进行了封装,实现了一个面向对象的数据库编程接口,使 VC++的数据库变得更加容易。 本章首先对 MFC ODBC 的概貌进行简要介绍,然后讲述利用 MFC ODBC 进行数据库 开发的技巧,最后将通过具体数据库开发实例,详细讲述通过 MFC ODBC 开发数据库应 用程序的方法和过程。 6.1 了解 MFC ODBC MFC 是 Microsoft Foundation Class(微软基础类库)的缩写,它的设计目标是简化开 发人员的工作。MFC 使开发人员创建基于 Windows 的应用程序,而不必掌握下层的 Windows 体系结构。由于数据库应用程序是管理数据的重要方面,Microsoft 开发了 ODBC API 的封装程序,为 ODBC 编程提供了一个面向对象的方法。 MFC 对 ODBC 的封装主要是开发了 CDatabase 类和 CRecordSet 类。 6.1.1 CDatabase 类 CDatabase 类用于应用程序建立同数据源的连接。CDatabase 类包含一个 m_hdbc 变量, 它代表了数据源的连接句柄。如果要建立 CDatabase 类的实例,应先调用该类的构造函数, 再调用 Open 函数,通过调用,初始化环境变量,并执行与数据源的连接。关闭数据源连 接的函数是 Close。 CDatabase 类提供了对数据库进行操作的函数,为了执行事务操作,CDatabase 类提供 了 BeginTrans 函数,当全部数据都处理完成后,可以通过调用 CommitTrans 函数提交事务, 或者在特殊情况下通过调用 Rollback 函数将处理回退。 CDatabase 类提供的函数可以用于返回数据源的特定信息,例如通过 GetConnect 函数 返回在使用函数 Open 连接数据源时的连接字符串,通过调用 IsOpen 函数返回当前的 CDatabase 实例是否已经连接到数据源上,通过调用 CanUpdate 函数返回当前的 CDatabase 实例是否是可更新的,通过调用 CanTransact 函数返回当前的 CDatabase 实例是否支持事务 操作,等等。 总之,CDatabase 类为 C++数据库开发人员提供了 ODBC 的面向对象的编程接口。 6.1.2 CRecordSet 类 要实现对结果集的数据操作,就要用到 CRecordSet 类。CRecordSet 类定义了从数据库 接收或者发送数据到数据库的成员变量,CRecordSet 类定义的记录集可以是表的所有列, 也可以是其中的一列,这是由 SQL 语句决定的。 CRecordSet 类的成员变量 m_hstmt 代表了定义该记录集的 SQL 语句句柄,m_nFields
第6章MFC ODBC编程 成员变量保存了记录集中字段的个数,m nParams成员变量保存了记录集所使用的参数个 数。 CRecordSet的记录集通过CDatabase实例的指针实现同数据源的连接,即CRecordSet 的成员变量m pDatabase。 如果记录集使用了WHERE子句,m strFilter成员变量将保存记录集的WHERE子句 的内容,如果记录集使用了ORDER BY子句,m strSort成员变量将保存记录集的ORDER BY子句的内容。 由多种方法可以打开记录集,最常用的方法是使用Open函数执行一个SQL SELECT 语句。有如下四种类型的记录集: .CRecordset::dynaset: 动态记录集,支持双向游标,并保持同所连接的数据源同步,对数据的更新操作 可以通过一个fetch操作获取。 CRecordset::snapshot: 静态快照,一旦形成记录集,此后数据源的所有改变都不能体现在记录集里,应 用程序必须重新进行查询,才能获取对数据的更新。该类型记录集也支持双向游 标。 CRecordset::dynamic: 同CRecordset:dynaset记录集相比,CRecordset::dynamic记录还能在fetch操作里 同步其它用户对数据的重新排序。 .CRecordset::forwardOnly: 除了不支持逆向游标外,其它特征同CRecordset::snapshot相同。 6.2MF℃ODBC数据库访问技术 6.2.1记录查询 使用CRecordSet的Open()和Requery()成员函数可以实现记录查询。需要注意的是, 在使用CRecordSet的类对象之前,必须使用CRecordSet的成员函数Open()来获得有效的 记录集。一旦使用过Open(O函数,再次查询时使用Requery()函数就可以了。在调用Open() 函数时,如果已己经将一个打开的CDatabase对象指针传递给CRecordSet类对象的 m pDatabase成员变量,那么,CRecordSet类对象将使用该数据库对象建立ODBC连接: 否则,如果m pDatabase为空指针,对象就需要就新建一个CDatabase类对象并使其与缺 省的数据源相连,然后进行CRecordSet类对象的初始化.缺省数据源由GetDefaultConnect() 函数获得。也可以通过特定的SQL语句为CRecordSet类对象指定数据源,并以它来调用 CRecordSet类的Open()函数,例如: myRS.Open(AFX_DATABASE_USE_DEFAULT,strSQL); 如果没有指定参数,程序则使用缺省的SQL语句,即对在GetDefaultSQL()函数中指 定的SQL语句进行操作,代码如下: -113-
第 6 章 MFC ODBC 编程 -113- 成员变量保存了记录集中字段的个数,m_nParams 成员变量保存了记录集所使用的参数个 数。 CRecordSet 的记录集通过 CDatabase 实例的指针实现同数据源的连接,即 CRecordSet 的成员变量 m_pDatabase。 如果记录集使用了 WHERE 子句,m_strFilter 成员变量将保存记录集的 WHERE 子句 的内容,如果记录集使用了 ORDER BY 子句,m_strSort 成员变量将保存记录集的 ORDER BY 子句的内容。 由多种方法可以打开记录集,最常用的方法是使用 Open 函数执行一个 SQL SELECT 语句。有如下四种类型的记录集: CRecordset::dynaset: 动态记录集,支持双向游标,并保持同所连接的数据源同步,对数据的更新操作 可以通过一个 fetch 操作获取。 CRecordset::snapshot: 静态快照,一旦形成记录集,此后数据源的所有改变都不能体现在记录集里,应 用程序必须重新进行查询,才能获取对数据的更新。该类型记录集也支持双向游 标。 CRecordset::dynamic: 同 CRecordset::dynaset 记录集相比,CRecordset::dynamic 记录还能在 fetch 操作里 同步其它用户对数据的重新排序。 CRecordset::forwardOnly: 除了不支持逆向游标外,其它特征同 CRecordset::snapshot 相同。 6.2 MFC ODBC 数据库访问技术 6.2.1 记录查询 使用 CRecordSet 的 Open()和 Requery()成员函数可以实现记录查询。需要注意的是, 在使用 CRecordSet 的类对象之前,必须使用 CRecordSet 的成员函数 Open()来获得有效的 记录集。一旦使用过 Open()函数,再次查询时使用 Requery()函数就可以了。在调用 Open() 函数时,如果已经将一个打开的 CDatabase 对象指针传递给 CRecordSet 类对象的 m_pDatabase 成员变量,那么,CRecordSet 类对象将使用该数据库对象建立 ODBC 连接; 否则,如果 m_pDatabase 为空指针,对象就需要就新建一个 CDatabase 类对象并使其与缺 省的数据源相连,然后进行 CRecordSet 类对象的初始化。缺省数据源由 GetDefaultConnect() 函数获得。也可以通过特定的 SQL 语句为 CRecordSet 类对象指定数据源,并以它来调用 CRecordSet 类的 Open()函数,例如: myRS.Open(AFX_DATABASE_USE_DEFAULT,strSQL); 如果没有指定参数,程序则使用缺省的 SQL 语句,即对在 GetDefaultSQL()函数中指 定的 SQL 语句进行操作,代码如下:
第6章MFC ODBC编程 CString CMyRS:GetDefaultSQL() freturn_T("[Name],[Age]");} 对于GetDefaultSQL()函数返回的表名,对应的缺省操作是SELECT语句,例如: SELECT FROM BasicData,MainSize 在查询过程中,也可以利用CRecordSet类的成员变量m strFilter和m strSort来执行 条件查询和结果排序。m strFilter用于指定过滤字符串,存放着SQL语句中关键字WHERE 后的条件语句:m strSort用于指定用于排序的字符串,存放着SQL语句中关键字ORDER BY后的字符串。例如: myRS.m_strFilte="Name=刘鹏"; myRS.m_strSort="Age"; myRS.Requery(); 数据库查询中对应的SQL语句为: SELECT◆FROM BasicData,MainSize WHERE Name=刘鹏'ORDER BY Age 除了直接赋值给成员变量m strFilter以外,还可以通过参数化实现条件查询。利用参 化可以更直观、更方便地完成条件查询任务。参数化方法的步骤如下: (1)声明参变量,代码如下: CString strName; int nAge; (2)在构造函数中初始化参变量如下: strName=_T(""); nAge=0; m_nParams=2; (3)将参变量与对应列绑定,代码如下: pFX->SetFieldType(CFieldExchange::param) RFX_Text(pFX,_T("Name"),strName), RFX Single(pFX,T("Age"),nAge); 完成以上步骤之后就可以利用参变量进行条件查询了,代码如下: m_pmyRS->m_strFilter="Name=?AND age=?"; m_pmyRS->strName="刘鹏": m_pmyRS->nAge=26; m_pmyRS->Requery(); 参变量的值按绑定的顺序替换查询字串中的“?”通配符。 如果查询的结果是多条记录,可以利用CRecordSet类的成员函数Move(),MoveNext(), MovePrev(),MoveFirstO)和MoveLast0来移动记录光标。 6.2.2记录添加 使用AddNew()成员函数能够实现记录添加,需要注意的是,在记录添加之前必须保 证数据库是以允许添加的方式打开的,代码如下: m_pmyRS>AddNew(),∥在表的末尾添加新记录 m_pmyRS->SetFieldNull(&(m_pSet->m_type),FALSE); -114-
第 6 章 MFC ODBC 编程 -114- CString CMyRS::GetDefaultSQL() {return _T("[Name],[Age]");} 对于 GetDefaultSQL()函数返回的表名,对应的缺省操作是 SELECT 语句,例如: SELECT * FROM BasicData,MainSize 在查询过程中,也可以利用 CRecordSet 类的成员变量 m_strFilter 和 m_strSort 来执行 条件查询和结果排序。m_strFilter 用于指定过滤字符串,存放着 SQL 语句中关键字 WHERE 后的条件语句;m_strSort 用于指定用于排序的字符串,存放着 SQL 语句中关键字 ORDER BY 后的字符串。例如: myRS.m_strFilter="Name='刘鹏'"; myRS.m_strSort="Age"; myRS.Requery(); 数据库查询中对应的 SQL 语句为: SELECT * FROM BasicData,MainSize WHERE Name='刘鹏' ORDER BY Age 除了直接赋值给成员变量 m_strFilter 以外,还可以通过参数化实现条件查询。利用参 化可以更直观、更方便地完成条件查询任务。参数化方法的步骤如下: (1) 声明参变量,代码如下: CString strName; int nAge; (2) 在构造函数中初始化参变量如下: strName =_T(""); nAge =0; m_nParams=2; (3) 将参变量与对应列绑定,代码如下: pFX->SetFieldType(CFieldExchange::param) RFX_Text(pFX,_T("Name"), strName); RFX_Single(pFX,_T("Age"), nAge); 完成以上步骤之后就可以利用参变量进行条件查询了,代码如下: m_pmyRS->m_strFilter="Name=? AND age=?"; m_ pmyRS -> strName ="刘鹏"; m_ pmyRS ->nAge=26; m_ pmyRS ->Requery(); 参变量的值按绑定的顺序替换查询字串中的“?”通配符。 如果查询的结果是多条记录,可以利用 CRecordSet 类的成员函数 Move(),MoveNext(), MovePrev(),MoveFirst()和 MoveLast()来移动记录光标。 6.2.2 记录添加 使用 AddNew()成员函数能够实现记录添加,需要注意的是,在记录添加之前必须保 证数据库是以允许添加的方式打开的,代码如下: m_ pmyRS ->AddNew(); // 在表的末尾添加新记录 m_ pmyRS ->SetFieldNull(&(m_pSet->m_type), FALSE);
第6章MFC ODBC编程 m_pmyRS->m_strName=-"刘鹏",∥输入新的字段值 m_pmyRS->m_nAge=26,∥输入新的字段值 m_pmyRS>Update(O,∥将新记录存入数据库 m_pmyRS->Requery(),∥重新建立记录集 6.2.3记录删除 调用Delete()成员函数能够实现记录删除,在调用Delete(O函数后不需调用Update()函 数,代码如下: m_pmyRS->DeleteO; if(!m_pmyRS->IsEOFO) m_pmyRS->MoveNext(): else m_pmyRS->MoveLast(); 6.2.4记录修改 调用Edit)成员函数可以实现记录修改,在修改完成后需要调用Update()将修改结果存 入数据库,代码如下: m_pmyRS->Edit(); ∥修改当前记录 m_pmyRS->m_strName-="刘波";∥修改当前记录字段值 m_pmyRS->Update(); ∥将修改结果存入数据库 m_pmyRS->Requery(); 6.2.5撤销数据库更新操作 如果用户增加或者修改记录后希望放弃当前操作,可以在调用Update(0函数之前调用 Move0函数,就可以使数据库更新撤销了,代码如下: m_pmyRS->Move(AFX_MOVE_REFRESH,SQL_FETCH_RELATIVE):/∥撤消操作 该函数用于撤消增加或修改模式,并恢复在增加或修改模式之前的当前记录。其中参 数AFX MOVE REFRESH的值为零。 6.2.6直接执行SQL语句 虽然通过CRecordSet类我们可以完成大多数的数据库查询操作,而且在CRecordSet 类的Open().成员函数中也可以提供SQL语句,但有的时候我们还想进行一些其他操作,例 如建立新表、删除表、建立新的字段等等,这时就需要用到CDatabase类的直接执行SQL 语句的机制。通过调用CDatabase类的ExecuteSQL()成员函数就能够完成QL语句的直接 执行,代码如下: BOOL CMyDB::ExecuteSQLWithReport(const CString&strSQL) { TRY -115-
第 6 章 MFC ODBC 编程 -115- m_ pmyRS ->m_strName="刘鹏"; // 输入新的字段值 m_ pmyRS ->m_nAge=26; // 输入新的字段值 m_ pmyRS -> Update(); // 将新记录存入数据库 m_ pmyRS ->Requery(); // 重新建立记录集 6.2.3 记录删除 调用 Delete()成员函数能够实现记录删除,在调用 Delete()函数后不需调用 Update()函 数,代码如下: m_ pmyRS ->Delete(); if (!m_ pmyRS ->IsEOF()) m_ pmyRS ->MoveNext(); else m_ pmyRS ->MoveLast(); 6.2.4 记录修改 调用 Edit()成员函数可以实现记录修改,在修改完成后需要调用 Update()将修改结果存 入数据库,代码如下: m_ pmyRS ->Edit(); // 修改当前记录 m_ pmyRS ->m_strName="刘波"; // 修改当前记录字段值 ... m_ pmyRS ->Update(); // 将修改结果存入数据库 m_ pmyRS ->Requery(); 6.2.5 撤销数据库更新操作 如果用户增加或者修改记录后希望放弃当前操作,可以在调用 Update()函数之前调 用 Move()函数,就可以使数据库更新撤销了,代码如下: m_ pmyRS ->Move(AFX_MOVE_REFRESH, SQL_FETCH_RELATIVE);//撤消操作 该函数用于撤消增加或修改模式,并恢复在增加或修改模式之前的当前记录。其中参 数 AFX_MOVE_REFRESH 的值为零。 6.2.6 直接执行 SQL 语句 虽然通过 CRecordSet 类我们可以完成大多数的数据库查询操作,而且在 CRecordSet 类的 Open()成员函数中也可以提供 SQL 语句,但有的时候我们还想进行一些其他操作,例 如建立新表、删除表、建立新的字段等等,这时就需要用到 CDatabase 类的直接执行 SQL 语句的机制。通过调用 CDatabase 类的 ExecuteSQL()成员函数就能够完成 QL 语句的直接 执行,代码如下: BOOL CMyDB::ExecuteSQLWithReport (const CString& strSQL) { TRY {
第6章MFC ODBC编程 m_pMyDB->ExecuteSQL(strSQL),∥直接执行SQL语句 } CATCH(CDBException,e) { CString strMsg; strMsg.LoadString(IDS EXECUTE SQL FAILED); strMsg+=strSQL; return FALSE; END CATCH return TRUE; 需要注意的是,由于不同DBMS提供的数据操作语句不尽相同,直接执行SQL语句 可能会破坏软件的DBMS无关性,因此在应用中应当慎用此类操作。 6.2.7MFC0DBC的数据库操作过程 同ODBC API编程类似,MFC的ODBC编程也要先建立同ODBC数据源的连接,这 个过程由一个CDatabase对象的Open函数实现。然后CDatabase对象的指针将被传递到 CRecordSet对象的构造函数里,使CRecordSet对象与当前建立起来的数据源连接结合起 来。 完成数据源连接之后,大量的数据库编程操作将集中在记录集的操作上。CRecordSet 类的丰富的成员函数可以让开发人员轻松地完成基本的数据库应用程序开发任务。 当然,完成了所有的操作之后,在应用程序退出运行状态的时候,需要将所有的记录 集关闭,并关闭所有同数据源的连接。 6.3 MFC ODBC编程实例 6.3.1实例概述 需求调查与分析 某贸易公司经理需要对公司日常处理的业务通过计算机进行监控,因此需要开发一个 浏览数据和报表的数据库应用软件,该软件的主要功能是数据表示和报表。数据的内容包 括公司日常的销售报告、产品情况、客户情况、雇员情况以及与公司合作的运货商的情况, 数据报表的主要目的是能够将浏览的信息以报表的方式打印出来。 数据库系统及其访问技术 在本实例里,我们采用MFC的ODBC数据库访问技术,从Access数据库里读取公司 销售信息、产品情况、客户信息、雇员信息以及与公司合作的运货商的信息。这是一个小 型的数据库应用,使用Access数据库就足够了。在这个实例里,我们借助MFC对ODBC -116-
第 6 章 MFC ODBC 编程 -116- m_pMyDB->ExecuteSQL(strSQL); // 直接执行 SQL 语句 } CATCH (CDBException,e) { CString strMsg; strMsg.LoadString(IDS_EXECUTE_SQL_FAILED); strMsg+=strSQL; return FALSE; } END_CATCH return TRUE; } 需要注意的是,由于不同 DBMS 提供的数据操作语句不尽相同,直接执行 SQL 语句 可能会破坏软件的 DBMS 无关性,因此在应用中应当慎用此类操作。 6.2.7 MFC ODBC 的数据库操作过程 同 ODBC API 编程类似,MFC 的 ODBC 编程也要先建立同 ODBC 数据源的连接,这 个过程由一个 CDatabase 对象的 Open 函数实现。然后 CDatabase 对象的指针将被传递到 CRecordSet 对象的构造函数里,使 CRecordSet 对象与当前建立起来的数据源连接结合起 来。 完成数据源连接之后,大量的数据库编程操作将集中在记录集的操作上。CRecordSet 类的丰富的成员函数可以让开发人员轻松地完成基本的数据库应用程序开发任务。 当然,完成了所有的操作之后,在应用程序退出运行状态的时候,需要将所有的记录 集关闭,并关闭所有同数据源的连接。 6.3 MFC ODBC 编程实例 6.3.1 实例概述 需求调查与分析 某贸易公司经理需要对公司日常处理的业务通过计算机进行监控,因此需要开发一个 浏览数据和报表的数据库应用软件,该软件的主要功能是数据表示和报表。数据的内容包 括公司日常的销售报告、产品情况、客户情况、雇员情况以及与公司合作的运货商的情况, 数据报表的主要目的是能够将浏览的信息以报表的方式打印出来。 数据库系统及其访问技术 在本实例里,我们采用 MFC 的 ODBC 数据库访问技术,从 Access 数据库里读取公司 销售信息、产品情况、客户信息、雇员信息以及与公司合作的运货商的信息。这是一个小 型的数据库应用,使用 Access 数据库就足够了。在这个实例里,我们借助 MFC 对 ODBC
第6章MFC ODBC编程 封装类CRecordset,从该类派生应用程序里使用的CCommonRs类。以CCommonRs类为 基础,实现对ODBC数据源的数据访问。 实例实现效果 ODBCDemo2是本书用于阐述MFC ODBC数据库编程的实例应用程序,该应用程序 实现了对某销售公司日常销售业务的信息浏览和报表操作。应用程序运行界面如图6-1所 示。 无标重商品们售管班系筑 回× 文件售报告D 产品吧容户©覆员自活货商①报表)查看心帮助山 DPCE 客户D公司名称 联系人姓超联系人头枪地址装市地区端码国家电话 传真 Bon app 13008 91244540 9124,4541 Bottom-Dor Ma... 23T 504)5554723 04)555m BSBEV B's Beverages 销售代表 Faunde..London EC2 5NT (1715551212 Cactus Comias P... Patndo Smpcon 101355555 (10135-4892 CENTC Centro comeraa... rc0年mg 5T书,-+10, 05022 (5)555392 5)5557293 Yang Wang 物 3012 瑞士 0452-076545 Pedro Aforso 钠善员 05432-043巴西 (11)555-747 Corscidated Hold e的Brown 钠售代表 eakk.…London WX1 6LT 英 (171)55s Cradherbut Dek.. Sve otteb 采购员 wase...Aschen 5206 0241-059428 Du monde enper Jenine Labrune 物王 67,rue...Nartes 44000 法国 0.67.68.88 4067.日989 EASTC Eastemn Cornection Ann Devon 的售代理 35Km.. London WK36FW关国 (171)555-0297 (171)555.… ERNSH Ernst Handel Roland Mend月 销墙经理 kKM0g94G里 8010 7675-3425 7675-3426 FAMIA Famla Arqubald力 Arla Cruez 市场助理 Rua Or P3P 05442-030巴西 (11)555-3857 月5SA FISSA Fabrica inte... Dlego Roe 结经理 C/Mor...Madnid 28034 西班牙 (91)5559444 91)5555 FOLIG Foles gourmanoes Martne Ranc 助理,1B4,C: e 59000 法国 20,16.10.16 20.1610.17 FOLKO Fok och fHB Mara Larsson 物王, erga,已r钟g 584467 0695-345721 FRANK Frankeriversand Peter Franoen 市纯经理 Beriner...Miechen 80805 089-0877310 089-0877451 FRANR France restauraton Ca十e5hmtt 市巧理 54,nuc..Nartes 44000 法国 40,322121 40322120 FRANS FranchiS.p.A. Paolo Aocortt 销售代表 va Mo.Torio 10100 意大利011-496因260 0114969251 ARB Furia Bacshau e F...Uno Rodriguez 销喜经理 rdm.Usboa 1675 着曹于(1)354-2534 (10354-2535- 致字滚动 图6-1 ODBCDemo2实例应用程序的运行界而 6.3.2实例实现过程 数据库设计 我们利用Microsoft Access工具设计本实例的数据库结构。在本实例里,我们需要利用 数据库存放销售公司的如下信息: ·日常销售信息:指公司日常销售帐单中的客户信息、雇员信息、订购日期、货主 信息、运货商信息。 ·产品信息:指公司现经营产品的产品名称、供应商信息、类别信息、单价以及库 存量等信息。 客户信息:指公司客户的客户名称、联系人信息和客户的地址信息。 ·雇员信息:指公司雇员的雇员姓名、头衔、尊称、出生日期、雇佣日期、联系信 息及其上级等信息。 ·供应商信息:指与公司合作的供应商的名称、地址、联系人等信息。 ·运货商信息:指与公司合作的运货商的名称、电话信息。 ·产品类别信息:指公司所经营产品的类别。 我们为数据库设计了八个表,表“订单”和表“订单明细”存放公司日常销售信息, 表“产品”存放公司的产品信息,表“客户”存放公司的客户信息,表“雇员”存放公司 的雇员信息,表“供应商”存放公司的产品供应商信息,表“运货商”存放公司的运货商 信息,表“类别”存放公司经营产品的类别信息。为了便于数据访问,我们还定义了三个 -117-
第 6 章 MFC ODBC 编程 -117- 封装类 CRecordset,从该类派生应用程序里使用的 CCommonRs 类。以 CCommonRs 类为 基础,实现对 ODBC 数据源的数据访问。 实例实现效果 ODBCDemo2 是本书用于阐述 MFC ODBC 数据库编程的实例应用程序,该应用程序 实现了对某销售公司日常销售业务的信息浏览和报表操作。应用程序运行界面如图 6-1 所 示。 图 6-1 ODBCDemo2 实例应用程序的运行界面 6.3.2 实例实现过程 数据库设计 我们利用 Microsoft Access 工具设计本实例的数据库结构。在本实例里,我们需要利用 数据库存放销售公司的如下信息: 日常销售信息:指公司日常销售帐单中的客户信息、雇员信息、订购日期、货主 信息、运货商信息。 产品信息:指公司现经营产品的产品名称、供应商信息、类别信息、单价以及库 存量等信息。 客户信息:指公司客户的客户名称、联系人信息和客户的地址信息。 雇员信息:指公司雇员的雇员姓名、头衔、尊称、出生日期、雇佣日期、联系信 息及其上级等信息。 供应商信息:指与公司合作的供应商的名称、地址、联系人等信息。 运货商信息:指与公司合作的运货商的名称、电话信息。 产品类别信息:指公司所经营产品的类别。 我们为数据库设计了八个表,表“订单”和表“订单明细”存放公司日常销售信息, 表“产品”存放公司的产品信息,表“客户”存放公司的客户信息,表“雇员”存放公司 的雇员信息,表“供应商”存放公司的产品供应商信息,表“运货商”存放公司的运货商 信息,表“类别”存放公司经营产品的类别信息。为了便于数据访问,我们还定义了三个
第6章MFC ODBC编程 视图,“SalesByCustomer'”视图管理着以客户为统计方式的销售信息,“SalesByEmployee” 视图管理着以雇员为统计方式的销售信息,“SalesByProduct'”视图管理着以产品为统计方 式的销售信息。 下面的表6-1列出了表“订单”的结构,表6-2列出了表“订单明细”的结构,表6-3 列出了表“产品”的结构,表6-4列出了表“客户”的结构,表6-5列出了表“雇员”的 结构,表6-6列出了表“供应商”的结构,表6-7列出了表“运货商”的结构,表6-8列出 了表“类别”的结构。 表6-1表“订单”的结构 字段名称 类型 字段名称 类型 订单ID(key) 自动编号 运货费 货币 客户ID 文本 货主名称 文本 雇员D 数字 货主地址 文本 订购日期 日期/时间 货主城市 文本 到货日期 日期/时间 货主地区 文本 发货日期 日期/时间 货主邮政编码 文本 运货商 数字 货主国家 文本 表6-2 表“订单明细”的结构 字段名称 类型 字段名称 类型 订单D 自动编号 数量 数字 产品D 数字 折扣 数字 单价 货币 表6-3表“产品”1 的结构 字段名称 类型 字段名称 类型 产品ID(key) 自动编号 单价 货币 产品名称 文本 库存量 数字 供应商D 数字 订购量 数字 类别D 数字 再订购量 数字 单位数量 文本 中止 是否 表6-4表“客户”的结构 字段名称 类型 字段名称 类型 客户ID(key) 自动编号 地区 文本 公司名称 文本 邮政编码 文本 联系人姓名 文本 国家 文本 联系人头衔 文本 电话 文本 地址 文本 传真 文本 城市 文本 -118-
第 6 章 MFC ODBC 编程 -118- 视图,“SalesByCustomer”视图管理着以客户为统计方式的销售信息,“SalesByEmployee” 视图管理着以雇员为统计方式的销售信息,“SalesByProduct”视图管理着以产品为统计方 式的销售信息。 下面的表 6-1 列出了表“订单”的结构,表 6-2 列出了表“订单明细”的结构,表 6-3 列出了表“产品”的结构,表 6-4 列出了表“客户”的结构,表 6-5 列出了表“雇员”的 结构,表 6-6 列出了表“供应商”的结构,表 6-7 列出了表“运货商”的结构,表 6-8 列出 了表“类别”的结构。 表 6-1 表“订单”的结构 字段名称 类型 字段名称 类型 订单 ID(key) 自动编号 运货费 货币 客户 ID 文本 货主名称 文本 雇员 ID 数字 货主地址 文本 订购日期 日期/时间 货主城市 文本 到货日期 日期/时间 货主地区 文本 发货日期 日期/时间 货主邮政编码 文本 运货商 数字 货主国家 文本 表 6-2 表“订单明细”的结构 字段名称 类型 字段名称 类型 订单 ID 自动编号 数量 数字 产品 ID 数字 折扣 数字 单价 货币 表 6-3 表“产品”的结构 字段名称 类型 字段名称 类型 产品 ID(key) 自动编号 单价 货币 产品名称 文本 库存量 数字 供应商 ID 数字 订购量 数字 类别 ID 数字 再订购量 数字 单位数量 文本 中止 是/否 表 6-4 表“客户”的结构 字段名称 类型 字段名称 类型 客户 ID(key) 自动编号 地区 文本 公司名称 文本 邮政编码 文本 联系人姓名 文本 国家 文本 联系人头衔 文本 电话 文本 地址 文本 传真 文本 城市 文本
第6章MFC ODBC编程 表6-5表“雇员”的结构 字段名称 类型 字段名称 类型 名字D 自动编号 因家 文本 头衔 文本 邮政编码 文本 尊称 文本 家庭电话 文本 出生日期 日期/时间 分机 文本 雇用日期 日期/时间 照片 OLE对象 地址 文本 备注 备注 城市 文本 上级 文本 地区 文本 表6-6表“供应商”的结构 字段名称 类型 字段名称 类型 供应商Dkey) 自动编号 地区 文本 公司名称 文本 邮政编码 文本 联系人姓名 文本 国家 文本 联系人头衔 文本 电话 文本 地址 文本 传真 文本 城市 文本 主页 超级链接 表6-7 表“运货商”的结构 字段名称 类型 字段名称 类型 运货商D(key) 自动编号 电话 货币类型 公司名称 文本 表6-8表“类别”的结构 字段名称 类型 字段名称 类型 类别D 自动编号 说明 备注 类别名称 文本 图片 OLE对象 在实例光盘的Database目录下,stocks.mdb文件是存放公司销售信息的Access数据库 文件,读者可以查看这个文件,了解详细信息。 创建0 DBCDemo2工程 ODBCDemo2工程是一个基于单文档的应用程序,创建应用程序工程时需要选择基于 单文档的应用程序类型。 操作步骤: (I)打开VC+的工程创建向导。从VC+的菜单中执行“File>New”命令,将VC++6.0 工程创建向导显示出来。如果当前的选项标签不是Project,单击Project选项标签将它选中。 在左边的列表里选择MFC AppWizard(exe)项,在Project Name编辑区里输入工程名称 -119-
第 6 章 MFC ODBC 编程 -119- 表 6-5 表“雇员”的结构 字段名称 类型 字段名称 类型 名字 ID 自动编号 国家 文本 头衔 文本 邮政编码 文本 尊称 文本 家庭电话 文本 出生日期 日期/时间 分机 文本 雇用日期 日期/时间 照片 OLE 对象 地址 文本 备注 备注 城市 文本 上级 文本 地区 文本 表 6-6 表“供应商”的结构 字段名称 类型 字段名称 类型 供应商 ID(key) 自动编号 地区 文本 公司名称 文本 邮政编码 文本 联系人姓名 文本 国家 文本 联系人头衔 文本 电话 文本 地址 文本 传真 文本 城市 文本 主页 超级链接 表 6-7 表“运货商”的结构 字段名称 类型 字段名称 类型 运货商 ID(key) 自动编号 电话 货币类型 公司名称 文本 表 6-8 表“类别”的结构 字段名称 类型 字段名称 类型 类别 ID 自动编号 说明 备注 类别名称 文本 图片 OLE 对象 在实例光盘的 Database 目录下,stocks.mdb 文件是存放公司销售信息的 Access 数据库 文件,读者可以查看这个文件,了解详细信息。 创建 ODBCDemo2 工程 ODBCDemo2 工程是一个基于单文档的应用程序,创建应用程序工程时需要选择基于 单文档的应用程序类型。 操作步骤: (1) 打开 VC++的工程创建向导。从 VC++的菜单中执行“File>New”命令,将 VC++ 6.0 工程创建向导显示出来。如果当前的选项标签不是 Project,单击 Project 选项标签将它选中。 在左边的列表里选择 MFC AppWizard(exe)项,在 Project Name 编辑区里输入工程名称
第6章MFC ODBC编程 “ODBCDemo:2”,并在Location编辑区里调整工程路径,如图6-2所示。 New 3x Fles Projects Workspaces Other Documents DATL COM Appwuzard Project name rce Type Wizard ODBCDemo2 Location: Extended Stored Proc Wizard FADB_PROJECTODBCMFCOD hhh Appwizard ●ISAPI Extension Wizard Maketile MFC ActiveX ControlWizard FCreate new workspace MFC AppWizard (din Add to curront workspac MFC ApoWiard‘cxn] &New Database Wzard rf Utility Project onsole Platforms: OK Cancel 图6-2工程创建向导 (2)选择应用程序的框架类型。单击“工程创建向导”窗口的OK按钮,进入“MFC AppWizard-Step1”对话框。首先选择应用程序的框架类型。如图6-3所示。在本工程里, 选择“Single document”,保持资源的语言类型为“中文”,单击“Next>”按钮。 CAppweard-step1 ?x What type of application would you like to create? Single document r达ultiple documents CDlalog based Document/ylew architecture support? What language would you like your resources in? 中文I中回][APPWZCHS.DL) ”按钮,进入“MFC AppWizard-Step3of6”对话框。在对话框里选择如下两 项: ●None ·ActiveX Controls -120-
第 6 章 MFC ODBC 编程 -120- “ODBCDemo2”,并在 Location 编辑区里调整工程路径,如图 6-2 所示。 图 6-2 工程创建向导 (2) 选择应用程序的框架类型。单击“工程创建向导”窗口的 OK 按钮,进入“MFC AppWizard – Step 1”对话框。首先选择应用程序的框架类型。如图 6-3 所示。在本工程里, 选择“Single document”,保持资源的语言类型为“中文”,单击“Next >”按钮。 图 6-3 选择应用程序的框架类型 (3) 进入“MFC AppWizard – Step 2 of 6”对话框,设置应用程序数据库特性。在对话框 里选择 None,如图 6-4 所示。 (4) 设置应用程序对复杂文档的支持。在“MFC AppWizard – Step 2 of 6”对话框里,单 击“Next >”按钮,进入“MFC AppWizard – Step 3 of 6”对话框。在对话框里选择如下两 项: None ActiveX Controls
第6章MFC ODBC编程 MFC Appwizerd -Step 2 of6 ?× What database support would you like to include? Nane C Header files only C Database view without file support CDatabase vlew with file support If you include a database view.you must select a data source. Data Source No data source is selected. Cancel 图6-4设置应用程序数据库特性 如图6-5所示,单击“Next>”按钮。 MC Appwizard-step 3of6 None Container CMini-server Full-server CBoth container and server FActive gocsment server Active dociment contisiner Woud you llke support for compound fies? Y pliatsir No,thimnk you What other support would you lke to inclde? Automation 《Bak Next Enish Cancel 图6-5设置应用程序对复杂文档的支持 (⑤)进入“MFC AppWizard-Step4of6”对话框,设置应用程序的特征信息。如图6-6 所示对话框是工程的特征信息,在本例中,ODBCDemo2工程有如下特征: ·Docking toolbar ●Initial statusbar Printing and print preview ●3 D controls 。Normal (6)在“MFC AppWizard-Step4of6”对话框里单击“Next>”按钮,进入“MFC AppWizard-Step5of6”对话框,选择工程风格和MFC类库的加载方式。在对话框里设 置如下三项: ·MFC Standard -121-
第 6 章 MFC ODBC 编程 -121- 图 6-4 设置应用程序数据库特性 如图 6-5 所示,单击“Next >”按钮。 图 6-5 设置应用程序对复杂文档的支持 (5) 进入“MFC AppWizard – Step 4 of 6”对话框,设置应用程序的特征信息。如图 6-6 所示对话框是工程的特征信息,在本例中,ODBCDemo2 工程有如下特征: Docking toolbar Initial statusbar Printing and print preview 3D controls Normal (6) 在“MFC AppWizard – Step 4 of 6”对话框里单击“Next >”按钮,进入“MFC AppWizard – Step 5 of 6”对话框,选择工程风格和 MFC 类库的加载方式。在对话框里设 置如下三项: MFC Standard