属性名 类型 是否为主键 允许空 备注 sno char(8) 是 学号 sname varchar(10) 否 √ 姓名 age int 否 √ 年龄 dept char(4) 否 √ 所在系号 comment varchar(8) 否 √ 评语 基于 ADO 方式的实验步骤 此例中所用数据库与上例中相同; 此例中无需创建数据源。
属性名 |
类型 |
是否为主键 |
允许空 |
备注 |
sno |
char(8) |
是 |
学号 |
|
sname |
varchar(10) |
否 |
√ |
姓名 |
age |
int |
否 |
√ |
年龄 |
dept |
char(4) |
否 |
√ |
所在系号 |
comment |
varchar(8) |
否 |
√ |
评语 |
基于ADO方式的实验步骤
此例中所用数据库与上例中相同;
此例中无需创建数据源。
(1)创建VC应用程序
打开VC++6.0,新建工程。选择MFC AppWizard(exe),工程名为exec2,存放在D盘实验文件夹里。点击“确定”,在弹出的窗口中选择“基本对话框”,以后的步骤没有需要修改的地方,可以直接点击“完成。”这样一个基于基本对话框的工程就创建好了。
(2)界面设计
在工作区左边的树型结构中,选择ResourceView,展开Dialog节点,双击IDD_EXEC2_DIALOG,打开该对话框。在这里添加所需控件。如图17所示。
图17
为编辑框和列表框添加变量。在界面右键单击,选择“建立类向导”,弹出如图18所示窗口。
图18
本例中需要为编辑框IDC_AGE, IDC_COMMENT, IDC_DEPT, IDC_NAME, IDC_SNO,列表框IDC_LIST添加变量。以IDC_AGE为例,点击“ADD Variable”弹出如图19所示窗口。
图19
这里变量名为m_age,类型可从下拉框里选。添加变量完成之后类向导如图20所示。
图20
为按钮添加函数,双击按钮可为其添加函数,在exec2Dig.cpp文件里。
(3)与ADO相关的代码设计
引入ADO库文件,使用ADO前必须在工程的StdAfx.h头文件里用直接引入符号#import引入ADO库文件,以使编译器能正确编译。代码如下所示:
//加入ADO支持库
#import "C:\Program Files\Common Files\System\ado\msado15.dll" no_namespace rename("EOF","rsEOF")
//namespace是命名空间,这里不需要命名空间,主要是为了访问方便,在程序中可以直接访问ADO提供的Connection、Command和Recordset这三个COM接口
定义ADO连接、命令、记录集变量指针,在exec2Dlg.h文件的class CExec2Dlg : public CDialog方法中添加如下代码:
// 定义ADO连接、命令、记录集变量指针
_ConnectionPtr m_pConnection;
_CommandPtr m_pCommand;
_RecordsetPtr m_pRecordset;
// 该指针为整个应用程序共享,所以放在public下面。
初始化OLE/COM库环境。必须注意的是,ADO库是一组COM动态库,这意味应用程序在调用ADO前,必须初始化OLE/COM库环境。在MFC应用程序里,一个比较好的方法是在应用程序主类的OnInitDialog()成员函数里初始化OLE/COM库环境。
在本例中,在exec2.cpp文件的BOOL CExec2Dlg::OnInitDialog()成员函数里添加如下代码:
//初始化COM,创建ADO连接等操作
AfxOleInit();
m_pConnection.CreateInstance(__uuidof(Connection));
//在ADO操作中建议语句中要常用try...catch()来捕获错误信息,
//因为它有时会经常出现一些想不到的错误
try
{
//打开本地Sql Server库student
m_pConnection->Open("driver={SQL Server};Server=XP-201203132217\\SQLSERVER2005;Database=Student;UID=sa;PWD=yuzhongchun","","",adModeUnknown);
//Server后是服务器的计算机名,注意XP-201203132217\\SQLSERVER2005是双斜线啊,写错了就会返回 [Microsoft][ODBC SQL Server Driver][DBNETLIB]SQL Server 不存在或访问被拒绝
//Database后是数据库名
// UID="";PWD=""写入相应的用户名和密码,这里使用的是SQL server验证
}
catch(_com_error e)
{
AfxMessageBox("数据库连接失败!");
return FALSE;
}
在exec2Dlg.cpp文件中添加代码。
在#endif下面添加如下代码:
extern CExec2App theApp; // 在此引用应用类中的theApp来获取库连接指针
在BOOL CExec2Dlg::OnInitDialog()函数中添加如下代码:
// TODO: Add extra initialization here
//使用ADO创建数据库记录集
m_pRecordset.CreateInstance(__uuidof(Recordset));
// 在ADO操作中建议语句中要常用try...catch()来捕获错误信息,
// 因为它有时会经常出现一些想不到的错误
try
{
m_pRecordset->Open("SELECT * FROM s", // 查询s表中所有字段
m_pConnection.GetInterfacePtr(), // 获取库接库的IDispatch指针
adOpenDynamic,
adLockOptimistic,
adCmdText);
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
至此,与ADO相关的代码都已添加完了。下面在exec2Dlg.cpp文件中添加应用代码。
(4)与功能相关的代码设计
在界面上用到列表框,当鼠标点击列表框的某一行时,其中的数据能够在编辑框中显示出来,这要用到列表框的一个函数。添加此函数的方法如下:摁住Ctrl和w键,进入类向导,如图21所示。
图21
选择IDC_LIST,在右边的Messages下面选择LBN_SELCHANGE,然后点击“Add Function”按钮,最后点击“确定”按钮,即为列表框添加了此函数。具体代码如下:
//名称:OnSelchangeList
//功能:当每次选择新的记录时,都会移动指针到新的记录位置并将值显示出来
void CExec2Dlg::OnSelchangeList()
{
int curSel = m_list.GetCurSel();
_variant_t var,varIndex;
if(curSel
return;
try
{
// 先将指针移向第一条记录,然后就可以相对第一条记录来随意移动记录指针
m_pRecordset->MoveFirst();
m_pRecordset->Move(long(curSel));
var = m_pRecordset->GetCollect("sname");
if(var.vt != VT_NULL)
m_sname = (LPCSTR)_bstr_t(var);
var = m_pRecordset->GetCollect("age");
if(var.vt != VT_NULL)
m_age=(LPCSTR)_bstr_t(var);
var = m_pRecordset->GetCollect("sno");
if(var.vt != VT_NULL)
m_sno = (LPCSTR)_bstr_t(var);
var = m_pRecordset->GetCollect("dept");
if(var.vt != VT_NULL)
m_dept = (LPCSTR)_bstr_t(var);
var = m_pRecordset->GetCollect("comment");
if(var.vt != VT_NULL)
m_comment = (LPCSTR)_bstr_t(var);
UpdateData(false);
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
}
将数据库中的数据显示在列表框中,添加函数ListData()。添加的方法是,在工作区左边的树型结构中,选择ClassView,右键单击CExec2Dlg,在弹出的菜单中选择Add Member Function,出现如图22所示的窗口,类型为void,函数描述为ListData()。
图22
此函数的具体代码如下:
//名称:ListData
//功能:将数据库中的数据显示在列表框中
void CExec2Dlg::ListData()
{
_variant_t var;
CString strname,strage,strsno,strdept,strcom;
//清空列表框
m_list.ResetContent();
strname=strage=strsno=strdept=strcom="";
//在ADO操作中建议语句中要常用try...catch()来捕获错误信息,
//因为它有时会经常出现一些想不到的错误。
try
{
if(!m_pRecordset->BOF)
m_pRecordset->MoveFirst();
else
{
AfxMessageBox("表内数据为空");
return;
}
// 读入库中各字段并加入列表框中
while(!m_pRecordset->adoEOF)
{
var = m_pRecordset->GetCollect("sno");
if(var.vt != VT_NULL)
strsno = (LPCSTR)_bstr_t(var);
var = m_pRecordset->GetCollect("sname");
if(var.vt != VT_NULL)
strname = (LPCSTR)_bstr_t(var);
var = m_pRecordset->GetCollect("age");
if(var.vt != VT_NULL)
strage = (LPCSTR)_bstr_t(var);
var = m_pRecordset->GetCollect("dept");
if(var.vt != VT_NULL)
strdept = (LPCSTR)_bstr_t(var);
var = m_pRecordset->GetCollect("comment");
if(var.vt != VT_NULL)
strcom = (LPCSTR)_bstr_t(var);
m_list.AddString( strsno + " --> " +strname + " --> "+strage+ " --> "+ strdept+ " --> "+ strcom);
m_pRecordset->MoveNext();
}
// 默认列表指向第一项,同时移动记录指针并显示
m_list.SetCurSel(0);
OnSelchangeList();
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
}
插入按钮对应的函数代码如下:
//名称:OnWritedata
//功能:将编辑框中输入的学生信息插入到s表中
void CExec2Dlg::OnWritedata()
{
UpdateData();
if(m_sname == "" || m_sno == "")
{
AfxMessageBox("学号和姓名信息不能为空!");
return;
}
//在ADO操作中建议语句中要常用try...catch()来捕获错误信息,
//因为它有时会经常出现一些想不到的错误。
try
{
// 写入各字段值
m_pRecordset->AddNew();
m_pRecordset->PutCollect("sno", _variant_t(m_sno));
m_pRecordset->PutCollect("sname", _variant_t(m_sname));
m_pRecordset->PutCollect("age", atol(m_age));
m_pRecordset->PutCollect("dept", _variant_t(m_dept));
m_pRecordset->PutCollect("comment", _variant_t(m_comment));
m_pRecordset->Update();
AfxMessageBox("插入成功!");
// 更新显示其库内容
int nCurSel = m_list.GetCurSel();
ListData();
m_list.SetCurSel(nCurSel);
// 移动记录指针到新的位置
OnSelchangeList();
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
}
修改按钮对应的函数代码如下:
//名称:OnModify
//功能:修改学生信息
void CExec2Dlg::OnModify()
{
UpdateData(); // 更新对话框数据
if(m_list.GetCount() == 0)
{
AfxMessageBox("表中记录数为空!");
return;
}
else if(m_list.GetCurSel() m_list.GetCount())
m_list.SetCurSel(0);
// 修改当前记录的字段值
try
{
m_pRecordset->PutCollect("sno", _variant_t(m_sno));
m_pRecordset->PutCollect("sname", _variant_t(m_sname));
m_pRecordset->PutCollect("age", atol(m_age));
m_pRecordset->PutCollect("dept", _variant_t(m_dept));
m_pRecordset->PutCollect("comment", _variant_t(m_comment));
m_pRecordset->Update();
// 重新读入库记录更新显示
int nCurSel = m_list.GetCurSel();
ListData();
m_list.SetCurSel(nCurSel);
// 移动记录指针到新的位置
OnSelchangeList();
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
}
删除按钮对应的函数代码如下:
//名称:OnDelete
//功能:删除选中的学生信息
void CExec2Dlg::OnDelete()
{
if(m_list.GetCount() == 0)
return;
else if(m_list.GetCurSel() m_list.GetCount())
m_list.SetCurSel(0);
try
{
// 删除当前行记录
m_pRecordset->Delete(adAffectCurrent);
m_pRecordset->Update();
// 删除列表中当前值
int nCurSel = m_list.GetCurSel();
m_list.DeleteString(nCurSel);
if(nCurSel == 0 && (m_list.GetCount() != 0))
m_list.SetCurSel(nCurSel);
else if(m_list.GetCount() != 0)
m_list.SetCurSel(nCurSel-1);
// 移动记录指针到新的位置
OnSelchangeList();
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
}
查询按钮对应的函数代码如下:
//名称:OnQuery()
//功能:按照学号和姓名查询学生信息,如果只输入学号则只按照学号查询
//只输入姓名则只按照姓名查询,两者都没有输入则查询所有学生信息
void CExec2Dlg::OnQuery()
{
UpdateData(TRUE);
//构造Sql语句
//为简单考虑,这里只把学号和姓名作为查询条件
CString strSql;
if(m_sname != "" && m_sno != "")
strSql.Format("SELECT * FROM s WHERE sname = '%s' AND sno = '%s'",
m_sname,m_sno);
else if(m_sname != "" && m_sno == "")
strSql.Format("SELECT * FROM s WHERE sname = '%s'",m_sname);
else if(m_sname == "" && m_sno != "")
strSql.Format("SELECT * FROM s WHERE sno = '%s'",m_sno);
else
strSql = "SELECT * FROM s";
try
{
//先关闭已经打开的记录集对象
m_pRecordset->Close();
//根据新的Sql查询语句,重新打开记录集对象
m_pRecordset->Open(strSql.AllocSysString(),
theApp.m_pConnection.GetInterfacePtr(),
adOpenDynamic,
adLockOptimistic,
adCmdText);
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
//将查询后得到的新记录集显示出来
ListData();
}
刷新按钮对应的函数代码如下:
//名称:OnRefresh
//功能:刷新编辑框和列表框
void CExec2Dlg::OnRefresh()
{
m_sno="";
m_sname="";
m_age="";
m_dept="";
m_comment="";
m_list.ResetContent();
UpdateData(false);
}
(5)运行结果
图23