vs2019-MFC-ODBC使用者向导的手动实现

最近在一门课程中,要求学习使用MFC-ODBC,在操作时,发现在Visual Studio 2019版本中找不到MFC ODBC使用者向导,查了半天资料最后发现vs2019已弃用了这个wizard
vs2019-MFC-ODBC使用者向导的手动实现_第1张图片
并且我们能看到微软的NOTE:
vs2019-MFC-ODBC使用者向导的手动实现_第2张图片
But,how to create consumer manually?
作为这方面的新新手,经过不断尝试,找到了以下几种解决方案


NO.1-拷贝

第一种方法也是最简单的方法(简单但并不省事)

就是找到一台安装有旧版本vs的计算机(自己下载或者寻求同学的帮助),在这台机子上完成相关类的新建后,把自动生成的XXX.hXXX.cpp文件拷贝到自己的机子,导入,就可以继续操作了

NO.2-直接使用CRecordset类操作

对MFC ODBC编程主要有5个类,其中的CDatabase和CRecordset都是从基类CObject派生而来的。
CDatabase类用于建立应用程序与数据源的连接。
CRecordset类用于从数据源中选一组记录(记录集)。

也就是说,当我们进行MFC ODBC编程的时候,首先要利用CDatabase类建立同ODBC数据源的连接,接下来就用CRecordset类与当前建立的数据源绑定,此时关于数据库的编程操作都放到了记录集上,最后要关闭记录集以及同数据源的连接

根据这些,我们可以得出其实我们是可以直接使用CRecordset类来进行简单操作的,不必强求wizard自动生成的类。

接下来我们开始编程:

  • 前提:

    • vs项目:基于MFC的对话框程序
    • ODBC数据源:ODBCDemo 通过使用windows管理工具中ODBC Data Sources (32-bit)创建
    • pch.h头文件中添加#include
  • 建立连接

    //在XXXDlg.h文件中的XXXDlg类中加入
    public:
    	CDatabase m_db;    //数据库
    
    //在XXXDlg.cpp文件中 XXXDlg类的构造函数中加入
    if (!m_db.Open(_T("ODBCDemo"), FALSE, FALSE,L"ODBC;"))
    {
        AfxMessageBox(L"不能打开数据库");
    }
    
  • 初始化记录集并获取第一条记录

    //在XXXDlg.h文件中的XXXDlg类中加入
    public:
    	CRecordset* m_rs;   //记录集指针
    
    //在XXXDlg.cpp文件中 XXXDlg类的构造函数中加入
    if()
    {/*刚刚加入的if语句*/}
    else
    {
        m_rs = new CRecordset(&m_db);   //记录集指针
        m_rs->Open(CRecordset::snapshot, L"SELECT `sno`,`sname`,`ssex`,`sage`,`depart`  FROM `Student`");  //注意:这里的sql语句不能直接写表名(虽然帮助文档说可以,或许还需要其他代码)
        if (!m_rs->IsOpen())
        {
            AfxMessageBox(L"数据集创建失败");
        }
    }
    

    可以看到,我们要操作的表是ODBCDemo中的Student表:(表中数据仅供测试,并无实际意义)

  • 创建界面 如下图,编辑框分别为IDC_EXIT1-5,查询按钮为IDC_BUTTON1,并为其添加事件处理程序
    vs2019-MFC-ODBC使用者向导的手动实现_第3张图片vs2019-MFC-ODBC使用者向导的手动实现_第4张图片

  • 编写按钮响应代码,实现 每按一次查询按钮,从表中读一条数据,直到读完

    void CDateBaseCodeDlg::OnBnClickedButton1()    //为查询按钮自动生成的事件处理函数
    {
    	if (!m_rs->IsOpen())
    	{
    		AfxMessageBox(L"记录集已关闭");
    		return;
    	}
    	CDBVariant varValue;			           //用来存储字段的值  CDBVariant对象
    	short nFields = m_rs->GetODBCFieldCount(); //获取总共多少条记录
    	if (!m_rs->IsEOF())                        //判断是否还有记录
    	{
    		for (short i = 0; i < nFields; ++i)	   //循环获取当前记录中每个字段的值并显示
    		{
    			m_rs->GetFieldValue(i, varValue);
    			SetDlgItemTextW(IDC_EDIT1 + i, *varValue.m_pstringW);
    		}
    		m_rs->MoveNext();
    	}
    	else
    	{
    		AfxMessageBox(L"已无记录");    
    		m_rs->Close();
    		m_db.Close();
    	}
    }
    
  • 程序效果:
    vs2019-MFC-ODBC使用者向导的手动实现_第5张图片

  • PS:关于代码中用到的一些函数的具体使用可以参考vsHelpViewer或者文末链接


NO.3-构造CRecordset的派生类

其实vs之前的MFC-ODBC consumer wizard就是在帮我们做这个工作,那么我们自然也可以手动完成

在本例中,如下:(注意:注释掉的是 使用wizard会自动生成的代码,手写的时候可以选择不写)

// Student.h : CStudent 的声明
#pragma once
#include
class CStudent : public CRecordset
{
public:
	CStudent(CDatabase* pDatabase = NULL);
	//DECLARE_DYNAMIC(CStudent)
	// 字段/参数数据
	CStringW	m_sno;
	CStringW	m_sname;
	CStringW	m_ssex;
	CStringW	m_sage;
	CStringW	m_depart;
	// 重写
public:
	virtual CString GetDefaultConnect();	// 默认连接字符串
	virtual CString GetDefaultSQL(); 	// 记录集的默认 SQL
	virtual void DoFieldExchange(CFieldExchange* pFX);	// RFX 支持
// 实现
/*
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif
*/
};
// Student.h : CStudent 类的实现
#include "pch.h"
#include "Student.h"
//IMPLEMENT_DYNAMIC(CStudent, CRecordset)
CStudent::CStudent(CDatabase* pdb):CRecordset(pdb)
{
	m_sno = L"";
	m_sname = L"";
	m_ssex = L"";
	m_sage = L"";
	m_depart = L"";
	m_nFields = 5;
	//m_nDefaultType = dynaset;  记录集默认类型
}
//#error Security Issue: The connection string may contain a password
CString CStudent::GetDefaultConnect()
{
	return _T("DSN=ODBCDemo;")
//DBQ=C:\\Users\\dell\\Desktop\\score_student.mdb;DriverId=25;FIL=MSAccess;MaxBufferSize=2048;PageTimeout=5;UID=admin;    连接字符串自定义
}
CString CStudent::GetDefaultSQL()
{
	return _T("[Student]");
}
void CStudent::DoFieldExchange(CFieldExchange* pFX)
{
	pFX->SetFieldType(CFieldExchange::outputColumn);
	RFX_Text(pFX, _T("[sno]"), m_sno);
	RFX_Text(pFX, _T("[sname]"), m_sname);
	RFX_Text(pFX, _T("[ssex]"), m_ssex);
	RFX_Text(pFX, _T("[sage]"), m_sage);
	RFX_Text(pFX, _T("[depart]"), m_depart);
}
/*
// CStudent 诊断
#ifdef _DEBUG
void CStudent::AssertValid() const
{
	CRecordset::AssertValid();
}
void CStudent::Dump(CDumpContext& dc) const
{
	CRecordset::Dump(dc);
}
#endif //_DEBUG
*/

通过观察可以发现,继承自CRecordset类的这个CStudent类关键在于以下几项:

  • 成员变量:和所选表字段一一对应的几个变量
  • 构造函数:初始化变量 并初始化 m_nFields(字段个数)(这个必须有)
  • GetDefaultConnect():返回默认的连接字符串
  • GetDefaultSQL():返回默认的sql查询语句(这里是可以直接写表名的)
  • DoFieldExchange(CFieldExchange* pFX):最关键的一个函数,把各个字段的值对应转换为CStudent类中各个成员变量的值

该类的使用就不必赘述了,记得Open()和Close()就好


总结

经过bz的一番折腾,get√到了这几种方法

  1. 得到自动生成的文件,并添加进项目中 ————这种方式……没什么多说的
  2. 直接使用CRecordset类进行操作 ————code相对来说简单,但可能会受到功能上的限制以及一些奇怪的bug
  3. 声明并实现CRecordset类的派生类 ————符合面对对象的设计方式,而且微软自己就是这样干的,不过code相对复杂

最后,bz也正在学习中,如果文章有错误欢迎大家指正,或者大家有更好的解决方案可以一起交流
希望能够帮到大家


参见:

  • Visual Studio 2019 版本 16.0 发行说明
  • CRecordset Class-官方文档
  • CRecordset类-csdn
  • CRecordset获取记录个数整理

你可能感兴趣的:(解决问题)