MFC 访问Access数据库 建立并执行存贮过程
在学习VC ADO访问数据库时,每次遇到带参数的查询或者存贮过程时,就比较反感,因为印象中好像就是SQl 才支持这些操作,因此在网上到处搜集关于Access中执行存贮过程和带参数查询的问题。可是网上很多帖子和作者,感觉讲的不够清楚,或者干脆不负责任的说Access不支持存贮过程,或者把这个过程说的过于复杂,好像很难一样。我通过之前学习《直接通过ADO操作Access数据库》(作者徐景周)以及查看了一些帖子之后,自己动手利用Access 2003 成功的建立了存贮过程 ,并且利用VC 可以进行方便的操作。在此我把所学习的内容分享给一些和我一样想快速入门的学生。
在Access 2003 中建立表的数据结构及初始化的数据:
在Access中建立存贮过程的代码和执行存贮过程的过程:
在VC中的代码:
注意我使用的是控件关联变量,说明如下
CListBox m_AccessList;//列表框控件 控件型
CString m_strClass;//学生的班级 字符串型
CString m_strName;//学生的姓名 字符串型
CString m_strSno;//学生的学号 字符串型
int m_nAge;//学生的年龄 整型
public:
_RecordsetPtr m_pRecordset;
_ConnectionPtr m_pConnection;
CEditRecord 是一个编辑记录输入对话框(class CEditRecord : public CDialog)如下:
其中的一些函数建立消息映射在此不列出,相信你做VC连接数据库操作,应该有这个基础.
一下是class CAdoDlg 的实现文件
// AdoDlg.cpp : implementation file
//
#include "stdafx.h"
#include "Ado.h"
#include "AdoDlg.h"
#include "EditRecord.h"
// CAdoDlg dialog
CAdoDlg::CAdoDlg(CWnd* pParent /*=NULL*/)
: CDialog(CAdoDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CAdoDlg)
m_strClass = _T("");
m_strName = _T("");
m_strSno = _T("");
m_nAge = 0;
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
// 初始化COM,创建ADO连接等操作
AfxOleInit();
m_pConnection.CreateInstance(__uuidof(Connection));
m_pRecordset.CreateInstance(__uuidof(Recordset));
}
/
// CAdoDlg message handlers
BOOL CAdoDlg::OnInitDialog()
{
//之前代码未作任何更改 由VC系统自动生成 此处不列出
// TODO: Add extra initialization here
InitData();//初始列表框数据
return TRUE; // return TRUE unless you set the focus to a control
}
//插入新记录
void CAdoDlg::OnBtnInsert()
{
// TODO: Add your control notification handler code here
try
{
// 写入各字段值
m_pRecordset->AddNew();
UpdateData();//千万记住要更新操作,从控件获取数据
CString strage;
strage.Format("%d",m_nAge);
m_pRecordset->PutCollect("学号", _variant_t (m_strSno));
m_pRecordset->PutCollect("姓名", _variant_t (m_strName));
m_pRecordset->PutCollect("年龄", _variant_t (strage));
m_pRecordset->PutCollect("班级", _variant_t (m_strClass));
m_pRecordset->Update();
LoadData(m_pRecordset);
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
}
//执行更新记录的存贮过程
void CAdoDlg::OnBtnMod()
{
// TODO: Add your control notification handler code here
// TODO: Add your control notification handler code here
_CommandPtr m_pCommand;//智能指针
m_pCommand.CreateInstance(__uuidof( Command ));//实例
//用_ParameterPtr智能指针来建立参数
_ParameterPtr m_pParam;
m_pParam.CreateInstance(__uuidof(Parameter));
//建立好参数
try
{ UpdateData();
m_pParam= m_pCommand->CreateParameter("Sno",adVarChar,adParamInput,15,(_variant_t)m_strSno);// 给参数设置各属性
m_pCommand->Parameters->Append(m_pParam);//学号 加入到Command对象的参数集属性中
m_pParam= m_pCommand->CreateParameter("Sname",adVarChar,adParamInput,20,(_variant_t)m_strName);
m_pCommand->Parameters->Append(m_pParam);//姓名 加入到Command对象的参数集属性中
m_pParam = m_pCommand->CreateParameter("Sage",adInteger,adParamInput,-1,(_variant_t)((long)m_nAge));
m_pCommand->Parameters->Append(m_pParam);//年龄 加入到Command对象的参数集属性中
m_pParam= m_pCommand->CreateParameter("Sclass",adVarChar,adParamInput,5,(_variant_t)m_strClass);
m_pCommand->Parameters->Append(m_pParam);//班级 加入到Command对象的参数集属性中
m_pCommand->CommandText="Proc_UpdateName";
m_pCommand->ActiveConnection=m_pConnection;
m_pCommand->Execute(NULL, NULL,adCmdStoredProc); // 执行更新数据存贮过程,注意此时不返回记录集
m_AccessList.ResetContent();
if(!m_pRecordset->adoEOF)
m_pRecordset->MoveFirst();
while(!m_pRecordset->adoEOF)
{
LoadData(m_pRecordset);
m_pRecordset->MoveNext();
}
}
catch(_com_error &e)
{
CString Error;
long i,cnt;
cnt=m_pConnection->Errors->Count;
Error+=e.ErrorMessage();
for(i=0;i<cnt;i++)
{
Error+=(LPCSTR)(m_pConnection->Errors->GetItem(_variant_t(i))->Description );
}
AfxMessageBox(Error);
}
}
//初始列表框数据
int CAdoDlg::InitData()
{
if(m_pConnection->IsolationLevel)
try
{
// 打开本地Access库
m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=STUMGR.mdb","","",adModeUnknown);
}
catch(_com_error e)
{
AfxMessageBox("数据库连接失败,确认数据库是否在当前路径下!",MB_OK|MB_ICONHAND);
return FALSE;
}
// 在ADO操作中建议语句中要常用try...catch()来捕获错误信息,
// 因为它有时会经常出现一些意想不到的错误。
try
{
m_pRecordset->Open("SELECT * FROM stu", // 查询stu表中所有字段
m_pConnection.GetInterfacePtr(), // 获取库接库的IDispatch指针
adOpenDynamic,
adLockOptimistic,
adCmdText);
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
_variant_t var;
CString strSno,strName,strClass;
try
{
if(!m_pRecordset->BOF)
m_pRecordset->MoveFirst();
else
{
AfxMessageBox("表内数据为空",MB_OK|MB_ICONHAND);
return FALSE;
}
// 读入库中各字段并加入列表框中
while(!m_pRecordset->adoEOF)
{
LoadData(m_pRecordset);
m_pRecordset->MoveNext();
}
// 默认列表指向第一项,同时移动记录指针并显示
m_AccessList.SetCurSel(0);
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
return TRUE;
}
//关闭对话框时释放数据库资源
void CAdoDlg::OnBtnClose()
{
// TODO: Add your control notification handler code here
CAdoDlg::OnClose();
}
void CAdoDlg::OnClose()
{
// TODO: Add your message handler code here and/or call default
if(IDOK==MessageBox("关闭数据库并推出吗?","学生管理",MB_OKCANCEL|MB_ICONEXCLAMATION))
{
try{
if(m_pConnection->State)
m_pConnection->Close();
m_pConnection= NULL;
if(m_pRecordset->State)
m_pRecordset->Close();
m_pRecordset = NULL;
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
CDialog::OnCancel();
}
}
//按年龄带参数的查询
void CAdoDlg::OnBtnQuery()
{
// TODO: Add your control notification handler code here
CString strSno,strName,strClass,strage;
int nAge;
//_RecordsetPtr pRecodrset(__uuidof(Recordset));
_CommandPtr m_pCommand;//还是智能指针
m_pCommand.CreateInstance(__uuidof( Command ));//实例
//VC中用_ParameterPtr智能指针来建立参数,具体如下:
_ParameterPtr m_pParam;
//m_pParam.CreateInstance("ADODB.Parameter");
//别高兴还没有真正的建立好参数
CEditRecord Dlg;
Dlg.m_strTip="输入年龄:";
if(IDOK==Dlg.DoModal())
{
nAge=atoi(Dlg.m_strInput);
// 方法一 一次性指定
//m_pParam = m_pCommand->CreateParameter("Age",adInteger,adParamInput,-1,(_variant_t)(long)nAge);//给参数设置各属性
//方法二
/*
_variant_t var;
var.vt=VT_INT;//先指定类型为整型
var.intVal =nAge;//赋值
m_pParam = m_pCommand->CreateParameter("Age",adInteger,adParamInput,-1,var);//给参数设置各属性
*/
//方法三
m_pParam = m_pCommand->CreateParameter("Age",adInteger,adParamInput,-1);//给参数设置各属性
m_pParam->Value = (_variant_t)((long)nAge);//后续指定
m_pCommand->Parameters->Append(m_pParam);//加入到Command对象的参数集属性中
m_pCommand->CommandText=(_bstr_t)("SELECT * FROM stu WHERE 年龄=?");
m_pCommand->ActiveConnection=m_pConnection;
try
{
m_pRecordset = m_pCommand->Execute(NULL, NULL,adCmdText); // 执行SQL语句,返回记录集
m_AccessList.ResetContent();
while(!m_pRecordset->adoEOF)
{
LoadData(m_pRecordset);
m_pRecordset->MoveNext();
}
}
catch(_com_error &e)
{
CString Error;
long i,cnt;
cnt=m_pConnection->Errors->Count;
Error+=e.ErrorMessage();
for(i=0;i<cnt;i++)
{
Error+=(LPCSTR)(m_pConnection->Errors->GetItem(_variant_t(i))->Description );
}
AfxMessageBox(Error);
}
}
}
//从记录集加载数据到列表框和编辑控件
void CAdoDlg::LoadData(_RecordsetPtr pRecordset)
{
int nAge;
CString strSno,strName,strClass,strAge;
if(!pRecordset->adoEOF)
{
_variant_t var;
var = m_pRecordset->GetCollect("学号");
if(var.vt != VT_NULL)
strSno = (LPCSTR)_bstr_t(var);
var = m_pRecordset->GetCollect("姓名");
if(var.vt != VT_NULL)
strName = (LPCSTR)_bstr_t(var);
var = m_pRecordset->GetCollect("年龄");
if(var.vt != VT_NULL)
nAge = atoi(_bstr_t(var));
strAge.Format("%d",nAge);
var = m_pRecordset->GetCollect("班级");
if(var.vt != VT_NULL)
strClass = (LPCSTR)_bstr_t(var);
m_AccessList.AddString( strSno+ " -->"+strName + "-->"+strAge+"-->"+strClass);
GetDlgItem(IDC_EDIT_SNO)->SetWindowText(strSno);
GetDlgItem(IDC_EDIT_NAME)->SetWindowText(strName);
GetDlgItem(IDC_EDIT_AGE)->SetWindowText(strAge);
GetDlgItem(IDC_EDIT_CLASS)->SetWindowText(strClass);
}
}
//按年龄的存贮过程查询
void CAdoDlg::OnBtnProcedure()
{
// TODO: Add your control notification handler code here
CString strSno,strName,strClass,strage;
int nAge;
//_RecordsetPtr pRecodrset(__uuidof(Recordset));
_CommandPtr m_pCommand;//智能指针
m_pCommand.CreateInstance(__uuidof( Command ));//实例
//用_ParameterPtr智能指针来建立参数
_ParameterPtr m_pParam;
//建立好参数
CEditRecord Dlg;
Dlg.m_strTip="输入年龄:";
try
{
if(IDOK==Dlg.DoModal())
{
nAge=atoi(Dlg.m_strInput);
m_pParam = m_pCommand->CreateParameter("Age",adInteger,adParamInput,-1);//给参数设置各属性
m_pParam->Value = (_variant_t)((long)nAge);
m_pCommand->Parameters->Append(m_pParam);//加入到Command对象的参数集属性中
m_pCommand->CommandText="Proc_QueryAge";
m_pCommand->ActiveConnection=m_pConnection;
m_pRecordset = m_pCommand->Execute(NULL, NULL,adCmdStoredProc); // 执行SQL语句,返回记录集
m_AccessList.ResetContent();
while(!m_pRecordset->adoEOF)
{
LoadData(m_pRecordset);
m_pRecordset->MoveNext();
}
}
}
catch(_com_error &e)
{
CString Error;
long i,cnt;
cnt=m_pConnection->Errors->Count;
Error+=e.ErrorMessage();
for(i=0;i<cnt;i++)
{
Error+=(LPCSTR)(m_pConnection->Errors->GetItem(_variant_t(i))->Description );
}
AfxMessageBox(Error);
}
}
实验中执行按年龄sql带参数查询和执行按年龄存贮过程的查询结果一样。示例如下:
当然本文只是提供了执行带参数的查询和存贮过程的简单例子,具体的应用还需要下功夫继续深究,代码已经测试通过,如遇问题,请修改你程序数据库路径、数据库数据类型、对话框结构。