MFC数据库Word文档格式.docx
《MFC数据库Word文档格式.docx》由会员分享,可在线阅读,更多相关《MFC数据库Word文档格式.docx(16页珍藏版)》请在冰点文库上搜索。
更多信息请查阅相关资料。
ADO。
面向对象的数据库访问技术,基于OLEDB,是一种高层的访问技术,速度快,易于使用。
在MFC中,ADO的许多使用方法类似于ODBC。
前面说了一些必要的废话,只是为了象征性的说明我们在应用一门技术的时候要掌握其基本原理和特征。
下面开始将怎么在XP+SQLServer2000+VC++6.0环境中编写一个基于ODBC的数据库程序,ADO在使用中和ODBC有许多的相似之处,了解了ODBC后再去学习ADO会是一件很轻松的事情。
要写一个数据库系统,首先要做的是注册数据源,控制面板管理工具中有数据源。
众所周知的事情就不说了。
建立一个数据库应用程序。
众所周知,在使用VC6编写MFC应用程序的时候先要建立工程。
我们手头的参考书中有说明如何建立一个ODBC的数据库应用程序,不再浪费文字过多描述。
书上的这个工程是一个单文档应用程序(貌似只中当文档应用程序在新建的时候可以添加数据源)。
工程建立完成后在CobjNameView(objName为工程名)类中会自动定义了一个“m_pSet”成员变量,这个变量的类型是CobjNameSet(objName为工程名),其父类为CRecordset,拿这个类出来说事是因为这个类负责了应用程序和数据库相关的操作,打开这个类,我们可以看见其中定义了成员变量为public,仔细观察就会发现这几个变量的名称,类型和数据源表中的属性一一对应了。
再看这个成员函数:
DoFieldExchange()。
和DoDataExchange()函数的功能很类似,不过一个是将变量(CobjNameSet类的几个数据成员)和数据库中某个元组的属性值关联,而另一个是将视图中的控件和某个变量项关联(是我们为控件添加变量的效果)。
这应该ODBC的数据交换机制(我想不出更好的词汇来形容它,手头可查资料太少),这种实现机制的使用使得我们可以只需要考虑程序中的变量值而不需要去管数据库中的属性名是什么。
MFC中对CRecordset:
:
Open()函数的定义如下:
virtualBOOLOpen(
UINTnOpenType=AFX_DB_USE_DEFAULT_TYPE,
LPCTSTRlpszSQL=NULL,
DWORDdwOptions=none
);
nOpenType打开方式,包括以下方式:
CRecordset:
dynaset
snapshot
dynamic
forwardOnly
lpszSQL,打开数据库的SQL语句。
dwOptions,操作方式,比如说是否是只读(CRecordset:
readOnly)。
当然,当我们使用MFC自动创建数据库连接的CRcordSet派生类的时候,并不需要我们显式的调用这个函数。
VC中创建MFCODBC应用程序的时候貌似也没有调用这个函数,不过事实是这样的,你的数据库在程序中刚开始就处于打开状态了,具体是怎么实现的我也不是很清楚,大概和这个类里面定义的GetDefaultConnect()成员函数和GetDefaultSQL()函数有关。
要点:
m_strFilter变量
CStringm_strFilter;
这个变量的作用体现在查找的时候。
变量的值取SQL的Select语句的WHERE关键字后面的部分,比如查找姓名为张三的学生:
Example:
m_pSet->
m_strFilter=_T(“sname=’张三’”);
Close();
Open();
while(m_pSet->
IsEOF()){
*/
出查询结果
/
_pSet->
MoveNext();
}
m_strFilter=_T(“”);
//这句很重要
从例子里可以猜测出,m_strFilter被赋予打开条件的字符串值之后,数据库被关闭再打开(事实上这个变量的作用只体现在打开的时候,因为程序中的数据库在一开始就是处于打开状态,所以才要先关闭数据库再打开,如果你不确定,可以使用CRcordSet:
IsOpen()函数进行判断),得到的元组集合(不知道怎么描述比较准确)就是符合m_strFilter条件的子表(感觉有点像是视图),我们可以对子表中的元组进行遍历等操作。
记得用完之后清空这个变量的值,要不你下次操作数据库的时候就看可能会遇见麻烦了。
这里还用到了另外两个函数:
voidClose();
BOOLIsEOF()const;
功能显然易见,不多少。
另外补充几个函数:
CRcordSet:
IsBOF();
是否到顶
IsOpen();
是否打开
CRcordSet:
MoveFirst();
移动到第一条记录
MoveLast();
移动到最后一条记录
easy了,ODBC中更新数据库是一件很轻松的事情,只要调用CRcordSet:
:
Edit()函数就OK了,看个简单的例子,出自MSDN:
//Toeditarecord,firstsetuptheeditbuffer
rsCustSet.Edit();
//Theneditfielddatamembersfortherecord
rsCustSet.m_BillingID=2795;
rsCustSet.m_ContactFirstName=_T("
JonesMfg"
//Finally,completetheoperation
if(!
rsCustSet.Update())
{
//Handlethefailuretoupdate
AfxMessageBox(_T("
Couldn'
tupdaterecord!
"
));
可以看见,更新数据库具有固定的“套用模式”,首先调用CRcordSet:
Edit()函数,如例子中所说,设置更新缓存,然后对对应变量的值进行修改,完成后调用CRcordSet:
Update()函数,完成更新,这时候程序会自动将修改的结果写入数据库而不用你操心。
当然,在更新数据库之前,你需要查找到你需要更新的元组(也称为记录),使用上面的查询方法。
函数:
virtualvoidAddNew();
一个简单的例子,说明一切问题:
m_pSet->
AddNew();
m_TestName=“TestName1”;
m_TestCode=“TestCode1”;
m_TestOthers=“OtherCodes”;
Update();
如你所见,代码又一次很荣幸的被“夹在”了AddNew()和Update()之间。
类似更新,首先告诉系统我要添加数据了(AddNew()),系统很无赖的给了你一块内存空间,让你可以对新的记录属性进行赋值,完了之后你又要告诉系统你已经搞定了,系统就不得不屁颠屁颠的去给你把数据写进数据库中(当然这之前会检测数据是否符合数据库的完整性约束)(Update())。
添加操作到此完成。
这个不带劲,没什么好说的,delete谁都认识。
virtualvoidDelete();
//CreateaderivedCRecordsetobject
CCustomerrsCustSet(&
m_dbCust);
rsCustSet.Open();
if(rsCustSet.IsEOF()||!
rsCustSet.CanUpdate()||
!
rsCustSet.CanTransact())
return;
m_dbCust.BeginTrans();
//Perhapsscrolltoanewrecord...
//Deletethecurrentrecord
rsCustSet.Delete();
//Finishedcommandsforthistransaction
if(IDYES==AfxMessageBox(_T("
Committransaction?
),MB_YESNO))
m_dbCust.CommitTrans();
else//Userchangedmind
m_dbCust.Rollback();
写的这么工整,肯定是出自MSDN了,这个家伙写的逻辑性很好。
看见许多新鲜的东西吧,别问我,我懒得说,自己想去。
额,你要看见的也就是从最后一行数起的第七行而已。
打开,关闭,更新,添加,删除,貌似我都说过了。
排序么,其实你不用在数据库中完成了。
方法一:
去程序里编写排序代码。
方法二:
m_strSort。
那个已经快被遗忘的SQL语句:
ORDERBY。
聪明的孩子,想到了m_strFilter了没?
没错,m_strSort变量的取值就是SQL语句ORDERBY后面的内容了,废话少说,看例子:
//Setthesortstring
rsCustSet.m_strSort=_T("
L_Name,ContactFirstName"
//Runthesortedquery
rsCustSet.Open(CRecordset:
snapshot,_T("
Customer"
出自MSDN。
额外说明,如果属性名(例子中是L_Name)包含空格的话,要用方括号括起来:
[LName],ContactFirstName"
Gotit?
程序中表名,数据库名亦然。
说了这么多其实都是VC帮我们建好了关联数据库的类,貌似我们在创建工程的时候只有在单文档工程中才能添加数据源,貌似也只是一个数据源,一个类。
万一我们要在一个对话框中使用数据库(例如登陆对话框),万一我们想添加多个数据源,多个Crecordset类的派生类,多个关联数据库的视图(CrecordView派生类)……
CDaoDatabaseclass和CdaoRecordsetclass
出于个人习惯,这里说“手动”连接数据库使用这两个类,当然你也可以使用CDatabaseclass和CRecordsetclass,用法差不多。
以写一个登陆对话框为例。
这里假定登陆对话框上有两个输入框,变量分别为m_username,m_password。
登陆确定按钮IDOK;
单选按钮:
IDC_RADIO1,IDC_RADIO2;
分别表示普通用户和管理员,为了节省时间,下面是本人的登录对话框IDOK按钮消息映射函数,仅供参考:
首先在文件顶部包含头文件:
#include<
afxdao.h>
;
voidCLoginDlg:
OnOK()
UpdateData(TRUE);
CDaoDatabasecdb;
CDaoRecordset*m_pSet;
COleVariantcv;
//CStringnullchar="
"
;
/*调用CdaoDatabase:
Open(),打开一个数据源(连接到一个数据库),并且分配相应的内存空间。
第一个参数为数据源名称,第二个参数为是否是独占模式打开,第三参数为是否已只读模式打开,最后一个参数,额,缺少必要资料,不是很清楚,MSDN中也只是说Astringexpressionusedforopeningthedatabase。
cdb.Open("
Student_Score"
FALSE,TRUE,"
ODBC=;
/*
初始化m_pSet变量,当然,这个必须要使用CDaoDatabase的对象来初始化,没什么好说的,函数调用而已。
m_pSet=newCDaoRecordset(&
cdb);
CStringSqlstr;
if(GetCheckedRadioButton(IDC_RADIO1,IDC_RADIO2)==IDC_RADIO1)
/*
如果登录用户选择的为学生
*/
这老长的一串其实只是在写打开的SQL语句而而已,有一个好用的Open()函数可以用,我们就不用神经质一样的打开数据库再去查找了,easy的方法,写一个SQL的select语句,查询条件为用户名和密码,显然用户名是唯一的。
用这个SQL语句做为Open()的第二个参数打开数据库。
Sqlstr="
selectStudentID,passwordfromStudentWhereStudentID='
+m_UID+"
'
ANDpassword='
+m_UPW+"
“正式的调用CdaoRecordset:
Open()”函数,第一个参数表示打开方式,动态打开,第二个参数为打开数据库的SQL语句,Open()函数在打开数据库时会自动按照这个字符串的条件筛选数据库的所有元组,并且返回符合条件的元组集合(记录集),这个字符串的功能和m_strFilter相似,最后一个参数:
nOptions,懒得说,0,NULL,随便你选。
m_pSet->
Open(dbOpenDynaset,Sqlstr,NULL);
if(!
IsEOF()){//用户名密码正确
/*判断依据?
如果表中有符合条件的元组(用户名密码正确),Open()函数必然返回一个非空的元组集合,这时候当然不可能就到了表的结尾了*/
isAdmin=false;
m_pSet->
cdb.Close();
CDialog:
OnOK();
}
else
MessageBox("
用户名或密码错误,\n请重新输入。
"
错误"
}
else{
selectAdminName,PasswordfromAdminwhereAdminName='
ANDPassword='
//MessageBox("
管理员登陆之后的界面"
isAdmin=true;
}
MessageBox("
VC6.0MFC工程中:
1.选择菜单栏InsertNewClass…
2.Baseclass选择CRecordset,编辑好类名,如图所示,单击“OK”,弹出“DatabaseOptions”对话框。
3.选择好数据源:
如图。
单击“OK”。
弹出“SelectDatabaseTables”对话框,选择数据库表。
4.如图所示,选择一个数据库的表,建议一次只选择一个表,操作起来方便一些。
5.好,现在你创建的类已经添加到工程中了,可以在ClassView中看见他了。
现在要说的就是如何使用它了。
首先要在要包含这个类的头文件例如TestInsetClass.h;
定义类的对象:
CtestInsetClass*m_pTestSet;
打开数据库:
m_pTestSet->
后面的操作和最前面所说的差不多了。
你可以很方便的进行查找,插入,更新,和删除。
你只需要使用父类的成员变量和函数:
m_strFilter、CRecordset:
AddNew()、CRecordset:
Update()、CRecordset:
Delete()。
6.用完之后记得关闭数据库。
插入CRecordView派生类
CRecordView的派生类是一个对话框。
在这里我们用这个对话框作为MianWnd的一个字窗口,如图:
操作步骤:
1.首先在ResourcesView的Dialog目录中右键,弹出快捷菜单选择Insert:
2.在弹出的“nsertResource”对话框中按图所示选择插入对话框为IDD_FORMVIEW,单击“New”插入对话框资源。
3.编辑好这个对话款资源。
为对话框添加类。
双击对话框资源或者右键选择“ClassWizard”,确定添加类后弹出“NewClass”对话框,基类(“BaseClass”)选择“CRecordView”就可以了。
4.确定后弹出如图对话框(名字N长,打字也很要命),选择前面添加的CRecordset派生类,确定。
5.使用CRecordView派生类对话框。
首先在classView中找到CclassNameApp类,找到其成员函数“InitInstance()”,双击打开,在其中找到如下代码:
CSingleDocTemplate*pDocTemplate;
pDocTemplate=newCSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTestDatabaseDoc),
RUNTIME_CLASS(CMainFrame),//mainSDIframewindow
RUNTIME_CLASS(CTestDatabaseView));
//注意这里
AddDocTemplate(pDocTemplate);
注意看代码中的倒数第二行,将其改为刚创建的CRecordView派生类对话款的类名,单击确定,编译运行程序,就可以看见窗口的视图改变了。
可以使用全局变量加if语句进行判断来动态改变窗口视图。