第 72 章
Edit 控件1 IDC_CONNECTION_STRING
Edit 控件2 IDC_EXECUTE_STRING
按钮控件1 IDC_SOURCE 数据源
按钮控件2 IDC_CONNECT 连接
按钮控件3 IDC_EXECUTE cāo作
按钮控件4 IDC_DISCONNECT 断开
按钮控件5 IDC_QUIT 退出
枫叶文学网www.fywxw.com
第12 章 数据库开发
·359·
4.编写代码
在正式开始编写代码之前,需要进一步明确此程序要实现的功能。用户单击“数据源”
按钮,则可以利用COM 组件DataSourceLocator 动态设置数据源,同时在Edit 控件1 中将连
接串显示出来。设定数据源后,用户单击“连接”按钮,程序连接到数据源,同时在List Box
控件中将数据库中所有表名都显示出来。然后用户可以在Edit 控件2 中输入SQL 语句,单
击“cāo作”按钮对数据库进行cāo作。当cāo作完毕后,单击“断开”按钮断开与数据源的连接。
最后单击“退出”按钮退出程序界面。同时为了方便用户,程序增加了两个功能。当用户在
List Box 控件中单击某个表名时,在DataGrid 控件中会相应的显示出此表的所有记录;当用
户在DataGrid 控件中表的某列单击时,此列按照升序进行排列,再次单击此列,则降序排列。
注意:为了让程序更加简洁,本节在介绍cāo作数据库时,没有利用12.6.4 小节介绍的对数据库记
录进行cāo作的方法,而是直接用SQL 语句cāo作。读者也可以根据12.6.4 小节所讲内容自己
编写cāo作记录的代码。
(1)初始化变量
首先在文件“CAdoTestView.h ” 的开头加入语句#include "datagrid.h" , 然后为类
CAdoTestView 添加如表12-25 所示的成员变量,它们都是public 成员变量。
表12-25 类CAdoTestView 成员变量表
成员变量 功能
_ConnectionPtr m_Connection 连接数据源
_RecordsetPtr m_Recordset 打开记录集
CListBox m_ListBox 与控件List Box 关联
CDataGrid m_DataGrid 与控件DataGrid 关联
CString m_strConnection 连接串,与Edit 控件1 关联
CString m_strSQL 对数据库cāo作的SQL 语句,与Edit 控件2 关联
CString m_strTableNcom 表名
BOOL isDesc 是否降序排列
然后在CAdoTestView 类的构造函数中先进行一些初始化工作,代码如下:
CAdoTestView::CAdoTestView()
: CFormView(CAdoTestView::IDD)
{
//{{AFX_DATA_INIT(CAdoTestView)
// NOTE: the ClassWizard will addcommber initialization here
//}}AFX_DATA_INIT
// TODO: add construction code here
m_strConnection = _T("");
m_strSQL = _T("");
m_strTableNcom = _T("");
isDesc = FALSE;
}
最后要将各控件和它们对应的变量关联起来,代码如下:
void CAdoTestView::DoDataExchange(CDataExchange* pDX)
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·360·
{
CFormView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAdoTestView)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
DDX_Control(pDX, IDC_LISTBOX, m_strListBox);
DDX_Control(pDX, IDC_DATAGRID, m_strDataGrid);
DDX_Text(pDX, IDC_CONNECTION_STRING, m_strConnection);
DDX_Text(pDX, IDC_EXECUTE_STRING, m_strSQL);
}
(2)编写各消息响应函数
前面已经说过,在编写ADO 的程序时,要用try 和catch,否则ADO 调用错误有可能使
程序崩溃,一定要随时记得捕捉_com_error 例外以及其他错误。因此首先编写捕获例外时的
处理函数。为类CAdoTestView 添加public 成员函数void GenerateError(HRESULT hr, PWSTR
pwszDescription),代码如下:
void CAdoTestView::GenerateError(HRESULT hr, PWSTR pwszDescription)
{
CString m_strError;
m_strError.Format("Run-tcom error ’%d (%x)’", hr, hr);
m_strError += "\n\r";
m_strError += pwszDescription;
AfxMessageBox(m_strError);
}
接下来为各个按钮添加响应函数。首先为用来设定数据源的按钮添加响应函数:打开
“ClassWizard”对话框,在“Class ncom”下拉菜单中选择CAdoTestView,在Object IDs 下
拉列表中选择IDC_SOURCE,在“Messages”下拉列表中选择BN_CLICKED,单击“Add
Function”,采用默认的函数名,然后依次单击“OK”和“Edit Code”按钮,定位到函数
CAdoTestView::OnSource(),代码如下:
void CAdoTestView::OnSource()
{
// TODO: Add your control notification handler code here
// TODO: Add your control notification handler code here
HRESULT hr;
IDataSourceLocatorPtr m_dlPrompt = NULL;
_ConnectionPtr m_Conn = NULL;
//初始化COM
::CoInitialize(NULL);
枫叶文学网www.fywxw.com
第12 章 数据库开发
·361·
//创建IDataSourceLocatorPtr 的实例
hr = m_dlPrompt.CreateInstance(__uuidof(DataLinks));
//弹出数据连接的对话框
m_Conn = m_dlPrompt->PromptNew();
if (m_Conn!=NULL)
{
//将连接字符串复制到m_strConnect 中
m_strConnection.Format("%s", (char*)m_Conn->ConnectionString);
//将变量中的值保存到控件中
UpdateData(FALSE);
}
}
编写好设置数据源的代码,接下来该为“连接”按钮编写响应函数了。在编写此函数之
前,先要编写数据库表名的函数。因为当连接成功时,在List Box 控件中会显示出数据库中
所有表的名称。为类CAdoTestView 添加一个函数void getTables(),它是public 的,用来显
示表名。代码如下:
void CAdoTestView::getTables()
{
_bstr_t tablesNcoms;
CString kooky;
//先将List Box 清空
m_ListBox.ResetContent();
//将控件中的值保存到变量中
UpdateData( TRUE);
try
{
//创建实例
m_Recordset.CreateInstance(__uuidof(Recordset));
//以只读方式打开结果集,得到表名信息
m_Recordset = m_Connection->OpenSchema (adSchemaTables,vtMissing,vtMissing);
//如果结果集没有结束
while (!m_Recordset->adoEOF)
{
//得到表项的名字
tablesNcoms = m_Recordset->GetCollect("TABLE_NAME");
kooky = (char*) tablesNcoms;
//如果是表项,则加到ListBox 中
if (kooky.Left(4) != "MSys")
m_ListBox.AddString( kooky );
//移到下一个表项
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·362·
m_Recordset->MoveNext();
}
}
//捕获例外_com_error
catch (_com_error &e)
{
GenerateError(e.Error(), e.Description());
}
//捕捉其他例外
catch(...) {}
//将变量中的值保存到控件中
UpdateData( FALSE );
//最后将结果集置为空
m_Recordset = NULL;
}
现在为“连接”按钮编写响应函数。具体步骤与为“数据源”按钮添加响应函数的一致,
只是Object IDs 下拉列表中选择Connect 按钮的ID:IDC_CONNECT,代码如下:
void CAdoTestView::OnConnect()
{
// TODO: Add your control notification handler code here
//更新变量值
UpdateData(TRUE);
try
{
//创建实例
m_Connection.CreateInstance(__uuidof(Connection));
//根据连接字符串开启数据连接
m_Connection->Open( _bstr_t( m_strConnection.GetBuffer(0) ), "", "", -1);
}
//捕获例外_com_error
catch (_com_error &e)
{
GenerateError(e.Error(), e.Description());
}
//捕捉其他例外
catch(...) {}
//将变量中的值保存到控件中
UpdateData( FALSE );
//显示表项名
getTables();
枫叶文学网www.fywxw.com
第12 章 数据库开发
·363·
}
按照顺序,为“cāo作”按钮编写响应函数。代码如下:
void CAdoTestView::OnExecute()
{
// TODO: Add your control notification handler code here
try
{
//创建实例
m_Recordset.CreateInstance(__uuidof(Recordset));
//将控件中的值保存到变量中,主要是保存SQL 语句
UpdateData(TRUE);
//设定光标服务
m_Connection->CursorLocation = adUseClient;
//根据连接字符串开启数据连接,得到结果集
m_Recordset->Open(m_strSQL.GetBuffer(0), m_Connection.GetInterfacePtr(), adOpenDynamic,
adLockOptimistic, adCmdText);
}
//捕获例外_com_error
catch (_com_error &e)
{
GenerateError(e.Error(), e.Description());
}
//捕获其他例外
catch (...) {}
//将结果集中的内容在datagrid 中显示出来
m_DataGrid.SetRefDataSource((LPUNKNOWN)m_Recordset);
//刷新DataGrid
m_DataGrid.Refresh();
//将变量中的值保存到控件中
UpdateData(FALSE);
//将结果集置空
m_Recordset = NULL;
}
在这段代码中,完成了执行SQL 语句。这是因为记录集转化成LPUNKNOWN 类型,然
后当做参数传给DataGrid 控件的方法SetRefDataSource 即可。
至此,程序已经可以完成对数据库的cāo作了,但是为了让程序更加完善,当cāo作结束时,
应该关闭记录集和连接,然后退出。最后还需要为“断开”和“退出”按钮编写响应函数。
“断开”按钮的响应函数如下:
void CAdoTestView::OnDisconnect()
{
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·364·
// TODO: Add your control notification handler code here
try
{
//关闭连接
m_Connection->Close();
}
//捕获_com_error 例外
catch (_com_error &e)
{
GenerateError(e.Error(), e.Description());
}
//捕获其他例外
catch(...) {}
//清空List Box 控件
m_ListBox.ResetContent();
//将DataGrid 控件置空
m_DataGrid.SetRefDataSource(NULL);
//将DataGrid 控件设置成默认状态
m_DataGrid.ClearFields();
//刷新DataGrid
m_DataGrid.Refresh();
//将SQL 语句清空
//这里不清空连接语句,是为了断开连接以后如果重新连接不需要重新设定数据源
m_strSQL = "";
//将变量值保存到控件中
UpdateData(FALSE);
}
为“退出”按钮编写如下响应函数:
void CAdoTestView::OnQuit()
{
// TODO: Add your control notification handler code here
try
{
//关闭记录集
if (m_Recordset != NULL)
m_Recordset->Close();
//关闭连接
if (m_Connection !=NULL)
m_Connection->Close();
}
枫叶文学网www.fywxw.com
第12 章 数据库开发
·365·
//捕获例外
catch(...){}
//退出
PostMessage(WM_QUIT);
}
至此,基本功能已经全部完成。为了让用户cāo作起来更加方便,下面介绍为添加的
松语文学免费小说阅读_www.16sy.com
Edit 控件2 IDC_EXECUTE_STRING
按钮控件1 IDC_SOURCE 数据源
按钮控件2 IDC_CONNECT 连接
按钮控件3 IDC_EXECUTE cāo作
按钮控件4 IDC_DISCONNECT 断开
按钮控件5 IDC_QUIT 退出
枫叶文学网www.fywxw.com
第12 章 数据库开发
·359·
4.编写代码
在正式开始编写代码之前,需要进一步明确此程序要实现的功能。用户单击“数据源”
按钮,则可以利用COM 组件DataSourceLocator 动态设置数据源,同时在Edit 控件1 中将连
接串显示出来。设定数据源后,用户单击“连接”按钮,程序连接到数据源,同时在List Box
控件中将数据库中所有表名都显示出来。然后用户可以在Edit 控件2 中输入SQL 语句,单
击“cāo作”按钮对数据库进行cāo作。当cāo作完毕后,单击“断开”按钮断开与数据源的连接。
最后单击“退出”按钮退出程序界面。同时为了方便用户,程序增加了两个功能。当用户在
List Box 控件中单击某个表名时,在DataGrid 控件中会相应的显示出此表的所有记录;当用
户在DataGrid 控件中表的某列单击时,此列按照升序进行排列,再次单击此列,则降序排列。
注意:为了让程序更加简洁,本节在介绍cāo作数据库时,没有利用12.6.4 小节介绍的对数据库记
录进行cāo作的方法,而是直接用SQL 语句cāo作。读者也可以根据12.6.4 小节所讲内容自己
编写cāo作记录的代码。
(1)初始化变量
首先在文件“CAdoTestView.h ” 的开头加入语句#include "datagrid.h" , 然后为类
CAdoTestView 添加如表12-25 所示的成员变量,它们都是public 成员变量。
表12-25 类CAdoTestView 成员变量表
成员变量 功能
_ConnectionPtr m_Connection 连接数据源
_RecordsetPtr m_Recordset 打开记录集
CListBox m_ListBox 与控件List Box 关联
CDataGrid m_DataGrid 与控件DataGrid 关联
CString m_strConnection 连接串,与Edit 控件1 关联
CString m_strSQL 对数据库cāo作的SQL 语句,与Edit 控件2 关联
CString m_strTableNcom 表名
BOOL isDesc 是否降序排列
然后在CAdoTestView 类的构造函数中先进行一些初始化工作,代码如下:
CAdoTestView::CAdoTestView()
: CFormView(CAdoTestView::IDD)
{
//{{AFX_DATA_INIT(CAdoTestView)
// NOTE: the ClassWizard will addcommber initialization here
//}}AFX_DATA_INIT
// TODO: add construction code here
m_strConnection = _T("");
m_strSQL = _T("");
m_strTableNcom = _T("");
isDesc = FALSE;
}
最后要将各控件和它们对应的变量关联起来,代码如下:
void CAdoTestView::DoDataExchange(CDataExchange* pDX)
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·360·
{
CFormView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAdoTestView)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
DDX_Control(pDX, IDC_LISTBOX, m_strListBox);
DDX_Control(pDX, IDC_DATAGRID, m_strDataGrid);
DDX_Text(pDX, IDC_CONNECTION_STRING, m_strConnection);
DDX_Text(pDX, IDC_EXECUTE_STRING, m_strSQL);
}
(2)编写各消息响应函数
前面已经说过,在编写ADO 的程序时,要用try 和catch,否则ADO 调用错误有可能使
程序崩溃,一定要随时记得捕捉_com_error 例外以及其他错误。因此首先编写捕获例外时的
处理函数。为类CAdoTestView 添加public 成员函数void GenerateError(HRESULT hr, PWSTR
pwszDescription),代码如下:
void CAdoTestView::GenerateError(HRESULT hr, PWSTR pwszDescription)
{
CString m_strError;
m_strError.Format("Run-tcom error ’%d (%x)’", hr, hr);
m_strError += "\n\r";
m_strError += pwszDescription;
AfxMessageBox(m_strError);
}
接下来为各个按钮添加响应函数。首先为用来设定数据源的按钮添加响应函数:打开
“ClassWizard”对话框,在“Class ncom”下拉菜单中选择CAdoTestView,在Object IDs 下
拉列表中选择IDC_SOURCE,在“Messages”下拉列表中选择BN_CLICKED,单击“Add
Function”,采用默认的函数名,然后依次单击“OK”和“Edit Code”按钮,定位到函数
CAdoTestView::OnSource(),代码如下:
void CAdoTestView::OnSource()
{
// TODO: Add your control notification handler code here
// TODO: Add your control notification handler code here
HRESULT hr;
IDataSourceLocatorPtr m_dlPrompt = NULL;
_ConnectionPtr m_Conn = NULL;
//初始化COM
::CoInitialize(NULL);
枫叶文学网www.fywxw.com
第12 章 数据库开发
·361·
//创建IDataSourceLocatorPtr 的实例
hr = m_dlPrompt.CreateInstance(__uuidof(DataLinks));
//弹出数据连接的对话框
m_Conn = m_dlPrompt->PromptNew();
if (m_Conn!=NULL)
{
//将连接字符串复制到m_strConnect 中
m_strConnection.Format("%s", (char*)m_Conn->ConnectionString);
//将变量中的值保存到控件中
UpdateData(FALSE);
}
}
编写好设置数据源的代码,接下来该为“连接”按钮编写响应函数了。在编写此函数之
前,先要编写数据库表名的函数。因为当连接成功时,在List Box 控件中会显示出数据库中
所有表的名称。为类CAdoTestView 添加一个函数void getTables(),它是public 的,用来显
示表名。代码如下:
void CAdoTestView::getTables()
{
_bstr_t tablesNcoms;
CString kooky;
//先将List Box 清空
m_ListBox.ResetContent();
//将控件中的值保存到变量中
UpdateData( TRUE);
try
{
//创建实例
m_Recordset.CreateInstance(__uuidof(Recordset));
//以只读方式打开结果集,得到表名信息
m_Recordset = m_Connection->OpenSchema (adSchemaTables,vtMissing,vtMissing);
//如果结果集没有结束
while (!m_Recordset->adoEOF)
{
//得到表项的名字
tablesNcoms = m_Recordset->GetCollect("TABLE_NAME");
kooky = (char*) tablesNcoms;
//如果是表项,则加到ListBox 中
if (kooky.Left(4) != "MSys")
m_ListBox.AddString( kooky );
//移到下一个表项
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·362·
m_Recordset->MoveNext();
}
}
//捕获例外_com_error
catch (_com_error &e)
{
GenerateError(e.Error(), e.Description());
}
//捕捉其他例外
catch(...) {}
//将变量中的值保存到控件中
UpdateData( FALSE );
//最后将结果集置为空
m_Recordset = NULL;
}
现在为“连接”按钮编写响应函数。具体步骤与为“数据源”按钮添加响应函数的一致,
只是Object IDs 下拉列表中选择Connect 按钮的ID:IDC_CONNECT,代码如下:
void CAdoTestView::OnConnect()
{
// TODO: Add your control notification handler code here
//更新变量值
UpdateData(TRUE);
try
{
//创建实例
m_Connection.CreateInstance(__uuidof(Connection));
//根据连接字符串开启数据连接
m_Connection->Open( _bstr_t( m_strConnection.GetBuffer(0) ), "", "", -1);
}
//捕获例外_com_error
catch (_com_error &e)
{
GenerateError(e.Error(), e.Description());
}
//捕捉其他例外
catch(...) {}
//将变量中的值保存到控件中
UpdateData( FALSE );
//显示表项名
getTables();
枫叶文学网www.fywxw.com
第12 章 数据库开发
·363·
}
按照顺序,为“cāo作”按钮编写响应函数。代码如下:
void CAdoTestView::OnExecute()
{
// TODO: Add your control notification handler code here
try
{
//创建实例
m_Recordset.CreateInstance(__uuidof(Recordset));
//将控件中的值保存到变量中,主要是保存SQL 语句
UpdateData(TRUE);
//设定光标服务
m_Connection->CursorLocation = adUseClient;
//根据连接字符串开启数据连接,得到结果集
m_Recordset->Open(m_strSQL.GetBuffer(0), m_Connection.GetInterfacePtr(), adOpenDynamic,
adLockOptimistic, adCmdText);
}
//捕获例外_com_error
catch (_com_error &e)
{
GenerateError(e.Error(), e.Description());
}
//捕获其他例外
catch (...) {}
//将结果集中的内容在datagrid 中显示出来
m_DataGrid.SetRefDataSource((LPUNKNOWN)m_Recordset);
//刷新DataGrid
m_DataGrid.Refresh();
//将变量中的值保存到控件中
UpdateData(FALSE);
//将结果集置空
m_Recordset = NULL;
}
在这段代码中,完成了执行SQL 语句。这是因为记录集转化成LPUNKNOWN 类型,然
后当做参数传给DataGrid 控件的方法SetRefDataSource 即可。
至此,程序已经可以完成对数据库的cāo作了,但是为了让程序更加完善,当cāo作结束时,
应该关闭记录集和连接,然后退出。最后还需要为“断开”和“退出”按钮编写响应函数。
“断开”按钮的响应函数如下:
void CAdoTestView::OnDisconnect()
{
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·364·
// TODO: Add your control notification handler code here
try
{
//关闭连接
m_Connection->Close();
}
//捕获_com_error 例外
catch (_com_error &e)
{
GenerateError(e.Error(), e.Description());
}
//捕获其他例外
catch(...) {}
//清空List Box 控件
m_ListBox.ResetContent();
//将DataGrid 控件置空
m_DataGrid.SetRefDataSource(NULL);
//将DataGrid 控件设置成默认状态
m_DataGrid.ClearFields();
//刷新DataGrid
m_DataGrid.Refresh();
//将SQL 语句清空
//这里不清空连接语句,是为了断开连接以后如果重新连接不需要重新设定数据源
m_strSQL = "";
//将变量值保存到控件中
UpdateData(FALSE);
}
为“退出”按钮编写如下响应函数:
void CAdoTestView::OnQuit()
{
// TODO: Add your control notification handler code here
try
{
//关闭记录集
if (m_Recordset != NULL)
m_Recordset->Close();
//关闭连接
if (m_Connection !=NULL)
m_Connection->Close();
}
枫叶文学网www.fywxw.com
第12 章 数据库开发
·365·
//捕获例外
catch(...){}
//退出
PostMessage(WM_QUIT);
}
至此,基本功能已经全部完成。为了让用户cāo作起来更加方便,下面介绍为添加的
松语文学免费小说阅读_www.16sy.com