众所周知VC++的MFC类库为编程者编制好了对数据库操作的类,编程者可以使用向导建立一个与数据库联结并对数据库进行操作的应用程序,不需要编制任何代码,这无疑为编程人员提供了一个捷径。但是,使用向导时只有选用基于单文档或多文档的项目才能选择数据源,与指定的的数据库相连,对用向导生成的基于对话框的应用程序不提供数据库的支持。即使是基于单文档或多文档的应用程序,当需要一些特殊的操作,例如,打开一个表,要求返回满足一定条件的记录集时,MFC并没有提供完全符合要求的现成函数。如果,能利用MFC所提供的数据库操作,再加上自己设计的函数,也就是说,设计一个对数据库操作的类,在程序中手工加入这个类,那么就可以在基于对话框的应用程序中实现对数据库的操作,而且,也可以针对自己应用程序的具体需要来设计类的函数,为特定功能的实现提供了很大的方便。
---- 在一个涉及数据库操作的应用程序中,常用到的MFC类有CdaoDatabase类、CdaoTableDef类、CdaoRecordset类和 CdaoQueryDef类,当对数据库进行操作时,需要先打开数据库,然后打开数据库中的表,再得到查询集和记录集。在自己定义的类中综合这四个类的操作,设计一个打开表得到查询集和记录集的函数,以后,在应用程序中使用该类时只需包含该类的头文件,所设计的函数就可以直接调用了。
---- 建立数据库类的过程可分为如下四步:
---- 一、定义一个无基类的CdataBaseOperate类
---- 1、在Workspace窗口选择ClassView选项卡,在树型类结构图的根部单击鼠标右键,选择New Class…,系统将弹出建立新类的对话框;
---- 2、在Class type中选择Generic Class;
---- 3、在Name中填写要建的新类的名称,要以大写字母C开头,系统会自动建立新类的头文件和实现文件,文件的名称为类名去掉第一个大写字母C,如果想改变文件的名称,可以单击change按钮.
---- 4、在填写好各项后,按OK按钮确定,一个无基类的新类建立成功,但,他还是一个空类,下一步,就要给类添加内容.
---- 二、在自定义的类中加入有关的定义
---- 1、在本应用程序中,使用ODBC与SQL SERVER的数据库相连,因而,在类的实现文件构造函数前加入如下的定义: #define SQL_DATABASE _T("ODBC;DSN=sql-database;UID=sa;PWD=pass;") DSN=sql-database表示建立的ODBC联接的名称是sql-database,如果选用其他数据库,只需在此改变与所需数据库建立的联接,或是重新配置sql-database 使之联接新的数据库。UID=sa;PWD=pass表示登录数据库的用户名是sa,密码是pass,如果密码是空则表示为PWD=""。
---- 2、在该类中综合使用到了MFC类库提供的有关数据库的几个类CdaoDatabase类、CdaoTableDef类、CdaoRecordset类和CdaoQueryDef类,而这四个类的定义和实现都包括在头文件afxdao.h中,因此,在新定义的类的头文件中一定要加上语句:
#include < afxdao.h >;
---- 3、对要用到的四个类各声明一个对象如下:
CDaoDatabase* loc_pDataBase;
CDaoTableDef* loc_pTable;
CDaoRecordset loc_pRecordset;
CDaoQueryDef* loc_pQueryDef;
---- 其中CdaoDatabase类、CdaoTableDef类和CdaoQueryDef类定义了对象指针,在使用时要先new,最后要delete。以CdaoDatabase类为例,在CdataBaseOperate类的构造函数中初始化对象指针 loc_pDataBase=new CDaoDatabase;在析构函数中要释放该指针delete loc_pDataBase;
---- 三、在自定义的类中加入所需的函数和变量
---- 手工加入函数包括两项工作,首先在头文件中加入函数的声明,然后,在实现文件中加入函数的具体实现,声明与实现一定要统一;
---- 使用向导加入函数和变量:
---- 1、在Workspace窗口选择ClassView选项卡;
---- 2、在树型类结构图的要添加函数和变量的类上单击鼠标右键,如果加入成员函数则单击Add Member Function,加入虚函数单击Add Virtual Function,加入成员变量单击 Add Member Variable;
---- 3、出现对话框后,填写成员函数或变量的名称、类型,系统会自动添加函数的声明与实现;
---- 4、添加函数的具体操作,可以通过编辑代码进一步填写;
---- 这些操作将会在Workspace窗口的ClassView选项中立即体现出来,并且,单击ClassView中的相应函数就可进入该函数的实现部分,进行进一步编写代码,如果做不到这一点,说明添加成员函数的操作有误。
---- 下面以本应用程序为例,给出具体的表结构和几个主要函数的实现,读者可以根据自己的实际情况设计函数。
---- 本应用程序中的一个典型表的结构是:
序号正题内容难度系数分值答案备注
整型字符型长整型双精度字符型字符型
---- 打开数据库的函数实现如下:
if (!loc_pDataBase->IsOpen())
loc_pDataBase->Open( NULL, FALSE,
FALSE, SQL_DATABASE);
---- 该函数中用到了CdaoDatabase类的两个函数IsOpen()和Open(NULL, FALSE, FALSE, SQL_DATABASE),因为已经声明了该类的指针对象loc_pDataBase,所以可以直接调用CdaoDatabase类的函数。其中,Open()函数中的最后一个参数SQL_DATABASE在前面已经介绍过,通过他打开相关的数据库。
---- 由于程序中打开表后,不仅要返回所有的记录集,还用到返回满足一定条件的记录集,因此打开表的函数除了带入表名外还有一个参数难度系数,lNDXS=0时,选择表中全部数据, lNDXS=1~n时,表示选择难度系数=1~n的记录。
bool CDataBaseOperate::OpenTable(CString strTableName,long lNDXS){CString strFieldNumber;loc_pTable=new CdaoTableDef(loc_pDataBase); if (!loc_pTable->IsOpen()) loc_pTable->Open(strTableName); //打开指定的表名strFieldNumber.Format("%d",loc_pTable- >GetFieldCount()); //得到字段数CString Sqlstr,Sqlstr1,Sqlstr2;loc_pQueryDef=new CDaoQueryDef(loc_pDataBase); //得到查询集和记录集if (lNDXS==0) { Sqlstr=_T("SELECT * FROM "+strTableName); }else { Sqlstr1="SELECT * FROM "+strTableName ; Sqlstr2.Format("WHERE 难度系数= %d",lNDXS); Sqlstr=_T(Sqlstr1+Sqlstr2); }loc_pQueryDef->Create(NULL,Sqlstr);loc_pRecordset.Open(loc_pQueryDef);m_nRecordNumber=0;while(!loc_pRecordset.IsEOF()) { m_nRecordNumber++; loc_pRecordset.MoveNext( ); } return TRUE; }
---- 为了维护数据库的安全,表用过后应该关闭,关闭表的同时,要释放在打开表的操作时初始化的对象指针,例如:delete loc_pQueryDef。同样要注意,在构造函数中初始化的对象指针,在析构函数中一定要释放。对象指针的初始化和释放是成对出现的。
loc_pDataBase=new CDaoDatabase;
//在构造函数中初始化对象指针。
delete loc_pDataBase;
//在析构函数中释放该对象指针。
---- 四、CdataBaseOperate类的应用
---- 1、使用VC++的向导生成一个应用程序,可以根据需要选择基于对话框或是基于单、多文档,选择单文档或多文档时不要选择数据库支持。
---- 2、在应用程序的主头文件中加入#include "DataBaseOperate.h",并且还要声明一个CdataBaseOperate类的对象,public: CDataBaseOperate m_CDataBaseOperate;
---- 3、有了指向CdataBaseOperate类的对象后,刚刚在CdataBaseOperate类中编制的函数都可以通过
"m_CdataBaseOperate.函数名"来调用。
小结:
---- 本文是VC++6.0下的CdataBaseOperate类建立与应用的一个初步探讨,CdataBaseOperate类所实现的功能是很强大的。除了介绍的CdataBaseOperate类的几个基本而又常用的函数之外,CdataBaseOperate还有很多用于其他方面的功能函数,在此不一一介绍。CdataBaseOperate类的函数,实现了数据库内容的显示、修改、添加、删除等功能,基本上满足了数据库操作人员的需要。除了这些,编程人员还可以根据程序的需要定义自己的特有的函数。
---- 本文所提供的程序均在VC++ 6.0中编译通过。
---- 附录:CdataBaseOperate类的头文件和原文件
附录:CdataBaseOperate类的头文件和原文件:
// DataBaseOperate.h: interface for the CDataBaseOperate class.//////////////////////////////////////////////////////////////////////#if !defined(AFX_DATABASEOPERATE_H__90468D61_8978_11D3_BA46_000021ECD4C4__INCLUDED_)#define AFX_DATABASEOPERATE_H__90468D61_8978_11D3_BA46_000021ECD4C4__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000#include <afxdao.h>class CDataBaseOperate {public:CDataBaseOperate();virtual ~CDataBaseOperate();CDaoDatabase* loc_pDataBase;CDaoTableDef* loc_pTable;CDaoRecordset loc_pRecordset;CDaoQueryDef* loc_pQueryDef;//以下的五个变量代表从一个数据库中得到一条记录的值CString m_strZTNRvalue,m_strDAvalue,m_strBZvalue;long m_nNDXSvalue;double m_nFZvalue;CString m_strTableName; //得到要打开的表名int m_nNumberPosition; //记住一开始带入的记录位置int m_nRecordNumber; //得到打开表的记录数bool OpenDataBase();bool OpenTable(CString strTableName); //打开表,带入表名bool CloseTable(); //在打开其他的表时,先关闭已打开的表//得到一条记录的值,值放在以上五个变量中,带入的参数为要得到的记录序号bool GetRecord(int nRecordPosition); //以下五个函数将带出一条记录的五个值CString GetZTNRvalue(); //得到正题内容字段值long GetNDXSvalue(); //得到难度系数字段值double GetFZvalue(); //得到分值字段值CString GetDAvalue(); //得到答案字段值CString GetBZvalue(); //得到备注字段值bool MoveFirst();bool MoveLast();bool MovePrev();bool MoveNext();};#endif // !defined(AFX_DATABASEOPERATE_H__90468D61_8978_11D3_BA46_000021ECD4C4__INCLUDED_)// DataBaseOperate.cpp: implementation of the CDataBaseOperate class.//////////////////////////////////////////////////////////////////////#include "stdafx.h"#include "NewCai.h"#include "DataBaseOperate.h"#ifdef _DEBUG#undef THIS_FILEstatic char THIS_FILE[]=__FILE__;#define new DEBUG_NEW#endif#define SQL_DATABASE _T("ODBC;DSN=sql-database;UID=sa;PWD="";")//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////CDataBaseOperate::CDataBaseOperate(){ loc_pDataBase=new CDaoDatabase;CString m_strFieldvalue;}CDataBaseOperate::~CDataBaseOperate(){ delete loc_pDataBase;}bool CDataBaseOperate::OpenDataBase(){ if (!loc_pDataBase->IsOpen())loc_pDataBase->Open( NULL, FALSE, FALSE, SQL_DATABASE ); return TRUE; }bool CDataBaseOperate::CloseTable(){ if (loc_pRecordset.IsOpen()){ loc_pRecordset.Close(); delete loc_pQueryDef; delete loc_pTable; }return TRUE;}bool CDataBaseOperate::MoveFirst(){ loc_pRecordset.MoveFirst();m_nNumberPosition=1;GetRecord(m_nNumberPosition);return TRUE;}bool CDataBaseOperate::MoveLast(){ loc_pRecordset.MoveLast();m_nNumberPosition=m_nRecordNumber;GetRecord(m_nNumberPosition);return TRUE;}bool CDataBaseOperate::MovePrev(){ loc_pRecordset.MovePrev();m_nNumberPosition--;if(loc_pRecordset.IsBOF()){ loc_pRecordset.MoveFirst(); m_nNumberPosition=1; }GetRecord(m_nNumberPosition);return TRUE;}bool CDataBaseOperate::MoveNext(){ m_nNumberPosition++;loc_pRecordset.MoveNext();if(loc_pRecordset.IsEOF()){ loc_pRecordset.MoveLast(); m_nNumberPosition=m_nRecordNumber; }GetRecord(m_nNumberPosition);return TRUE;}bool CDataBaseOperate::OpenTable(CString strTableName){ CString strFieldNumber;loc_pTable=new CDaoTableDef(loc_pDataBase); if (!loc_pTable->IsOpen()) loc_pTable->Open(strTableName); //打开指定的表名strFieldNumber.Format("%d",loc_pTable->GetFieldCount()); //得到字段数CString Sqlstr; //得到查询集和记录集loc_pQueryDef=new CDaoQueryDef(loc_pDataBase);Sqlstr=_T("SELECT * FROM "+strTableName);loc_pQueryDef->Create(NULL,Sqlstr);loc_pRecordset.Open(loc_pQueryDef);m_nRecordNumber=0;while(!loc_pRecordset.IsEOF()){ m_nRecordNumber++; loc_pRecordset.MoveNext( ); } return TRUE; }bool CDataBaseOperate::GetRecord(int nRecordPosition){ //得到字段名CDaoFieldInfo fieldinfo;CString strZTNRName,strNDXSName,strFZName,strDAName,strBZName;m_nNumberPosition=nRecordPosition;loc_pTable->GetFieldInfo(1,fieldinfo,AFX_DAO_PRIMARY_INFO);strZTNRName=fieldinfo.m_strName;loc_pTable->GetFieldInfo(2,fieldinfo,AFX_DAO_PRIMARY_INFO);strNDXSName=fieldinfo.m_strName;loc_pTable->GetFieldInfo(3,fieldinfo,AFX_DAO_PRIMARY_INFO);strFZName=fieldinfo.m_strName;loc_pTable->GetFieldInfo(4,fieldinfo,AFX_DAO_PRIMARY_INFO);strDAName=fieldinfo.m_strName;loc_pTable->GetFieldInfo(5,fieldinfo,AFX_DAO_PRIMARY_INFO);strBZName=fieldinfo.m_strName;int iNumber=1;COleVariant OleField;loc_pRecordset.MoveFirst();//得到指定记录的字段值,存入五个变量中while(!loc_pRecordset.IsEOF()){ if (iNumber==nRecordPosition) { loc_pRecordset.GetFieldvalue(strZTNRName,OleField); m_strZTNRvalue=(CString)V_BSTRT(&OleField); m_strZTNRvalue.TrimRight(); loc_pRecordset.GetFieldvalue(strNDXSName,OleField); m_nNDXSvalue=(long)V_I4(&OleField); loc_pRecordset.GetFieldvalue(strFZName,OleField); m_nFZvalue=(double)V_R8(&OleField); loc_pRecordset.GetFieldvalue(strDAName,OleField); m_strDAvalue=(CString)V_BSTRT(&OleField); m_strDAvalue.TrimRight(); loc_pRecordset.GetFieldvalue(strBZName,OleField); m_strBZvalue=""; m_strBZvalue=(CString)V_BSTRT(&OleField); m_strBZvalue.TrimRight(); loc_pRecordset.MoveLast(); loc_pRecordset.MoveNext(); } else { loc_pRecordset.MoveNext( ); iNumber++; }}loc_pRecordset.MoveFirst();int jj=1;while (jj<nRecordPosition){ loc_pRecordset.MoveNext(); jj++; }return TRUE;}CString CDataBaseOperate::GetZTNRvalue(){ return m_strZTNRvalue;}long CDataBaseOperate::GetNDXSvalue(){ return m_nNDXSvalue;}double CDataBaseOperate::GetFZvalue(){ return m_nFZvalue;}CString CDataBaseOperate::GetDAvalue(){ return m_strDAvalue;}CString CDataBaseOperate::GetBZvalue(){ return m_strBZvalue;}