MFC中最简单的数据库应用
acmilan2015/05/19软件综合 IP:四川
在计算机编程中,最实用的技术莫过于数据库应用了,特别是访问本地数据库的方法。可以说访问数据库是计算机编程的必备技能。在MFC中访问数据库其实很容易的。
首先,你需要一个*.mdb的数据库(不能是*.accdb),可以使用Microsoft Access来生成:
捕获.png

然后在里边新建一个表,添加一些字段,关闭
然后按照常规方法新建一个MFC工程(单文档、多文档、对话框均可,在这里我建立一个对话框程序):
捕获2.png

然后需要在stdafx.h里加入这一句,添加数据库支持:
<code class="lang-cpp">// 添加数据库支持
#include <afxdb.h></afxdb.h></code>
由于使用的是基于对话框的程序,因此需要手动添加数据库支持。随后打开资源视图找到主对话框,设计如下的界面:
捕获4.png

注意ComboBox组合框需要添加一个变量,这里设为m_combobox。然后分别双击四个按钮添加单击代码。

------- 我是讲解的分割线 -------

在MFC中,数据库有两个常用类:CDatabase和CRecordset。CDatabase用于打开数据库和执行SQL命令,而CRecordset则提供了一种直观的方法访问数据库记录。在这里我不准备给大家详细解读这两个类的用法,只教给大家比较简单的用法:如何打开数据库,执行SQL语句,遍历数据记录,关闭数据库。

一、如何打开本地数据库
打开本地数据库不是很难,只是要记住一个ODBC连接地址格式,格式如下:
"ODBC;Engine={引擎名称};DSN='';DBQ=文件名"
这个格式是固定的,其中我们用到的引擎是"Microsoft Access Driver (*.mdb)",即访问Access本地数据库。
由于程序中经常需要数据库,因此需要将数据库对象定义为对话框类(DataBaseTest1Dlg.h)中的一个类变量:
<code class="lang-cpp">CDatabase m_dbfile;</code>
代码如下:
<code class="lang-cpp">void CDataBaseTest1Dlg::OnBnClickedDbopen()
{
    CString sDriver = "Microsoft Access Driver (*.mdb)"; // 数据库引擎
    CString sFile = "Database.mdb"; // 数据库路径
    CString sConnect;
                                          
    // 用CString::Format构造数据库的连接地址
    sConnect.Format("ODBC;DRIVER={%s};DSN='';DBQ=%s",sDriver,sFile);
                                          
    // 构造后的地址:"ODBC;DRIVER={Microsoft Access Driver (*.mdb)};DSN='';DBQ=Database.mdb"
                                              
    // 建议在try块中进行数据库操作
    try
    {
        // 打开数据库(简单用法)
        m_dbfile.Open(NULL, false, false, sConnect);
                                          
        // TODO: 访问数据库
    }
    catch(CDBException &e) // 数据库失败时
    {
         AfxMessageBox("数据库连接失败,确认数据库Database.mdb是否在当前路径下!");
         return;
    }
                                              
}
                     
// CDatabase::Open()函数共有5个参数:
// 参数1是DSN地址,这里留空
// 参数2是独占连接,默认为false
// 参数3是只读连接,默认为false
// 参数4是连接地址
// 参数5是是否使用游标库,默认为true,这里省略</code>
访问数据库强烈建议在try catch块中进行,并捕捉CDBException,因为如果不捕捉很可能导致程序崩溃。

二、执行SQL语句
执行SQL语句很简单,直接使用ExecuteSQL("SQL语句")即可。如以下语句删除表datatable中的所有数据。
<code class="lang-cpp">m_dbfile.ExecuteSQL("DELETE FROM datatable");</code>

三、遍历数据记录
遍历数据记录要用到CRecordset,它提供了方便的访问数据记录的途径,建立CRecordset的方法:
<code class="lang-cpp">CRecordset recset(&m_dbfile);</code>
建立了记录集以后还要打开它,打开它需要一个SELECT查询:
<code class="lang-cpp">// 需要一个select查询语句以打开记录集
CString sqlstr =  "SELECT id, context FROM datatable ORDER BY id ASC";
            
recset.Open(CRecordset::forwardOnly, sqlstr, CRecordset::readOnly);
                    
// CRecordset::Open()函数共有3个参数:
// 参数1是打开类型,有forwardOnly、snapshot、dynaset、dynamic,默认是snapshot
// 参数2是SQL语句
// 参数3是打开选项,这里是readOnly,表示只读</code>
这里我们只需要遍历,因此选择了forwardOnly和readOnly模式。
打开以后便可以遍历了。遍历最简单的方法就是使用GetFieldValue("字段名", str1);来获取数据,并使用MoveNext()移动到下一条记录,使用IsEOF()判断是否遍历完毕:
<code class="lang-cpp">while (!recset.IsEOF()) { // 判断是否读取完毕
                                         
    // 通过 GetFieldValue("字段名", &str); 获取当前记录中各字段的数据
    CString strID;
    recset.GetFieldValue("id", strID);
                                         
    CString strContext;
    recset.GetFieldValue("context", strContext);
                                                                 
    // TODO: 使用获得的数据
                                         
    // 移向下一条记录
    recset.MoveNext();
}</code>
最后可以用Close()手动关闭记录集(一般不用手动关闭):
<code class="lang-cpp">recset.Close();</code>

四、关闭数据库也很简单,直接Close()即可。为了避免重复Close(),可以先用IsOpen()判断一下:
<code class="lang-cpp">if (m_dbfile.IsOpen()) { // 如果数据库已打开
    m_dbfile.Close(); // 关闭数据库
}</code>
这个IsOpen()函数也可以用在其它的数据库操作上,以避免在未打开数据库的情况下访问数据库。

------- 我是源代码的分割线 -------

附上源代码和例程(无毒):
程序运行效果图:
捕获5.png
attachment icon DataBaseTest1.rar 331.87KB RAR 120次下载

[修改于 8年11个月前 - 2015/05/24 22:57:56]

来自:计算机科学 / 软件综合
3
 
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
acmilan 作者
8年11个月前 IP:四川
769356
附上重要的程序源代码:
stdafx.h文件:
<code class="lang-cpp">// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
   
// ... 其它代码 ...
   
#include <afxdb.h></afxdb.h></code>
DataBaseTest1Dlg.h文件:
<code class="lang-cpp">// DataBaseTest1Dlg.h : 头文件
//
   
#pragma once
#include "afxwin.h"
   
// CDataBaseTest1Dlg 对话框
class CDataBaseTest1Dlg : public CDialog
{
    // ... 其它代码 ...
public:
    CComboBox m_combobox;
    CDatabase m_dbfile;
   
    // ... 其它代码 ...
};</code>
DataBaseTest1Dlg.cpp文件:
<code class="lang-cpp">// DataBaseTest1Dlg.cpp : 实现文件
//
  
// ... 其它代码 ...
  
void CDataBaseTest1Dlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_COMBO1, m_combobox);
}
     
// ... 其它代码 ...
     
void CDataBaseTest1Dlg::OnBnClickedAdd()
{
    CString str1;
    m_combobox.GetWindowText(str1);
    if (str1 != "") {
        m_combobox.AddString(str1);
        m_combobox.SetWindowText("");
        SuspendDataToDB(); // 更新数据库
    }
}
     
void CDataBaseTest1Dlg::OnBnClickedDel()
{
    int cur = m_combobox.GetCurSel();
    if (cur >= 0) { // 返回-1则没有选择任何对象
        m_combobox.DeleteString(cur);
        SuspendDataToDB(); // 更新数据库
    }
}
     
void CDataBaseTest1Dlg::OnBnClickedDbopen()
{
    CString sDriver = "Microsoft Access Driver (*.mdb)"; // 数据库引擎
    CString sFile = "Database.mdb"; // 数据库路径
    CString sConnect;
     
    // 构造数据库的连接地址
    sConnect.Format("ODBC;DRIVER={%s};DSN='';DBQ=%s",sDriver,sFile);
     
    // 构造后的地址:"ODBC;DRIVER={Microsoft Access Driver (*.mdb)};DSN='';DBQ=Database.mdb"
         
    // 建议在try块中进行数据库操作
    try
    {
        // 打开数据库(简单用法)
        // 参数1是DSN地址,这里留空
        // 参数2是独占连接,默认为false
        // 参数3是只读连接,默认为false
        // 参数4是连接地址
        // 参数5是是否使用游标库,默认为true
        m_dbfile.Open(NULL, false, false, sConnect);
     
        // 更改标题栏
        SetWindowText("数据库测试:数据库已连接");
     
        // 加载数据库内容到程序
        LoadDataFromDB();
    }
    catch(CDBException &e) // 数据库失败时
    {
         AfxMessageBox("数据库连接失败,确认数据库Database.mdb是否在当前路径下!");
         return;
    }
         
}
     
void CDataBaseTest1Dlg::OnBnClickedDbclose()
{
    if (m_dbfile.IsOpen()) { // 如果数据库已打开
        m_dbfile.Close(); // 关闭数据库
        SetWindowText("数据库测试:数据库已断开");
    }
}
     
void CDataBaseTest1Dlg::OnClose()
{
    if (m_dbfile.IsOpen()) {
        m_dbfile.Close();
        SetWindowText("数据库测试:数据库已断开");
    }
     
    CDialog::OnClose();
}
     
void CDataBaseTest1Dlg::SuspendDataToDB(void)
{
    if (m_dbfile.IsOpen()) { // 数据库操作
        try {
            CString strSql;
     
            // 删除所有记录
            m_dbfile.ExecuteSQL("DELETE FROM datatable");
     
            for (int i=0; i<m_combobox.getcount(); i++) {                                       依次取得组合框中的字符串                 cstring temp;                 m_combobox.getlbtext(i, temp); 依次插入                 strsql.format("insert into datatable (id, context) values (%d, '%s');", i,                 m_dbfile.executesql(strsql);             }         } catch (cdbexception &e)     } }      void cdatabasetest1dlg::loaddatafromdb(void)     if (m_dbfile.isopen()) 数据库操作                       记录集,可以方便地操作记录 crecordset的应用十分广泛,用法参见微软msdn         crecordset recset(&m_dbfile); 需要一个select查询语句以打开记录集         cstring sqlstr="  "SELECT" context from order by id asc"; 打开记录集: 参数1是打开类型,有forwardonly、snapshot、dynaset、dynamic,默认为snapshot 参数2是sql语句 参数3是打开选项,这里是readonly,表示只读         recset.open(crecordset::forwardonly, sqlstr, crecordset::readonly); 先清空组合框         m_combobox.resetcontent();         while (!recset.iseof()) 通过 getfieldvalue("字段名", &str); 获取当前记录中各字段的数据             cstring             recset.getfieldvalue("context", 向组合框添加所取得的值             m_combobox.addstring(temp); 移向下一条记录             recset.movenext(); }< code></m_combobox.getcount();></code>
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
wzbhbb
8年2个月前 IP:北京
811012
怎么无法下载?
另外,数据表建立是如何操作的
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
8年2个月前 修改于 8年2个月前 IP:四川
811053
引用 wzbhbb:
怎么无法下载?
另外,数据表建立是如何操作的
个人不再建议玩C++/Comctl32、C++/MFC、C++/ATL这些落后的GUI开发方法。。。

它们实在是效率太低、难度太高、自由度太低、界面太丑了。。。

建议去学习C#/WPF这种更高效、低难度、自由度更高、更华丽的GUI编程方法,或者跨平台的C++/Qt也行。。。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
所属分类
上级专业
同级专业
acmilan
进士 学者 笔友
文章
461
回复
2934
学术分
4
2009/05/30注册,5年2个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}