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


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


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


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

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

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

一、如何打开本地数据库
打开本地数据库不是很难,只是要记住一个ODBC连接地址格式,格式如下:
"ODBC;Engine={引擎名称};DSN='';DBQ=文件名"
这个格式是固定的,其中我们用到的引擎是"Microsoft Access Driver (*.mdb)",即访问Access本地数据库。
由于程序中经常需要数据库,因此需要将数据库对象定义为对话框类(DataBaseTest1Dlg.h)中的一个类变量:
CDatabase m_dbfile;
代码如下:
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,这里省略
访问数据库强烈建议在try catch块中进行,并捕捉CDBException,因为如果不捕捉很可能导致程序崩溃。

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

三、遍历数据记录
遍历数据记录要用到CRecordset,它提供了方便的访问数据记录的途径,建立CRecordset的方法:
CRecordset recset(&m_dbfile);
建立了记录集以后还要打开它,打开它需要一个SELECT查询:
// 需要一个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,表示只读
这里我们只需要遍历,因此选择了forwardOnly和readOnly模式。
打开以后便可以遍历了。遍历最简单的方法就是使用GetFieldValue("字段名", str1);来获取数据,并使用MoveNext()移动到下一条记录,使用IsEOF()判断是否遍历完毕:
while (!recset.IsEOF()) { // 判断是否读取完毕
                                         
    // 通过 GetFieldValue("字段名", &str); 获取当前记录中各字段的数据
    CString strID;
    recset.GetFieldValue("id", strID);
                                         
    CString strContext;
    recset.GetFieldValue("context", strContext);
                                                                 
    // TODO: 使用获得的数据
                                         
    // 移向下一条记录
    recset.MoveNext();
}
最后可以用Close()手动关闭记录集(一般不用手动关闭):
recset.Close();

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

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

附上源代码和例程(无毒):
程序运行效果图:
捕获5.PNG

DataBaseTest1.rar
332k
RAR
5次下载

[修改于 4 年前 - 2015-05-24 22:57:56]

来自 Windows
 
2015-5-19 04:33:43
acmilan(作者)
1楼
附上重要的程序源代码:
stdafx.h文件:
// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
   
// ... 其它代码 ...
   
#include <afxdb.h>
DataBaseTest1Dlg.h文件:
// DataBaseTest1Dlg.h : 头文件
//
   
#pragma once
#include "afxwin.h"
   
// CDataBaseTest1Dlg 对话框
class CDataBaseTest1Dlg : public CDialog
{
    // ... 其它代码 ...
public:
    CComboBox m_combobox;
    CDatabase m_dbfile;
   
    // ... 其它代码 ...
};
DataBaseTest1Dlg.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, temp);
                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 datatable 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 temp;
            recset.GetFieldValue("context", temp);
                 
            // 向组合框添加所取得的值
            m_combobox.AddString(temp);
     
            // 移向下一条记录
            recset.MoveNext();
        }
    }
}
折叠评论
加载评论中,请稍候...
折叠评论
2016-03-02 08:46:41
2016-3-2 08:46:41
2楼
怎么无法下载?
另外,数据表建立是如何操作的
折叠评论
加载评论中,请稍候...
折叠评论
acmilan(作者)
3楼
引用 wzbhbb:
怎么无法下载?
另外,数据表建立是如何操作的
个人不再建议玩C++/Comctl32、C++/MFC、C++/ATL这些落后的GUI开发方法。。。

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

建议去学习C#/WPF这种更高效、低难度、自由度更高、更华丽的GUI编程方法,或者跨平台的C++/Qt也行。。。

[修改于 4 年前 - 2016-03-02 20:43:43]

折叠评论
加载评论中,请稍候...
折叠评论

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

插入资源
全部
图片
视频
音频
附件
全部
未使用
已使用
正在上传
空空如也~
上传中..{{f.progress}}%
处理中..
上传失败,点击重试
{{f.name}}
空空如也~
(视频){{r.oname}}
{{selectedResourcesId.indexOf(r.rid) + 1}}
ID:{{user.uid}}
{{user.username}}
{{user.info.certsName}}
{{user.description}}
{{format("YYYY/MM/DD", user.toc)}}注册,{{fromNow(user.tlv)}}活动
{{submitted?"":"投诉"}}
请选择违规类型:
{{reason.description}}
支持的图片格式:jpg, jpeg, png