ODBC:开放式数据库连接,是为解决异构数据库(不同数据库采用的数据存储方法不同)共享而产生的。ODBC API相对来说非常复杂,这里介绍MFC的ODBC类。
添加ODBC用户DSN
首先,在计算机中添加用户DSN:(WIN10下,搜索ODBC)
点添加,以SQL Server为例,其他类似(MYSQL需要安装对应的ODBC驱动):
填写DSN名称、描述,IP地址(本机用127.0.0.1)
本机用windows用户登录,其他电脑可以使用用户名+密码登录:
选择对应的数据库(要注意!)
点完成后,测试一下数据源:
在ODBC中出现用户DSN,表明添加成功。
使用MFC ODBC类
创建工程-》单文档-》在数据库支持步,选择数据库:
点击数据源,选择上面添加的test :
点确定后,选择数据库中的表格(只能选择一张表):
点确定后,创建完工程,打开资源视图,在主视图中添加一些控件,用于显示数据库中数据:
注意控件与数据库中表格进行对应:(示例中显示数据库表中的四列)
修改视图代码,直接完成控件与数据库列的绑定:
在视图类中响应工具栏中的四个命令:
代码如下:
运行程序即可以看到数据库中数据(有一个安全警告,删除代码即可)
添加排序、搜索功能:
通过设置RecordSet的排序字段 m_strSort 重新查询数据库即可以完成按该关键字排序
通过设置RecordSet的排序字段 m_strFilter 则可以根据该字段对数据库进行搜索(其实就是where子句)
代码如下:
视图头文件:
// MFC10View.h : CMFC10View 类的接口
//
#pragma once
class CMFC10Set;
class CMFC10View : public CRecordView
{
protected: // 仅从序列化创建
CMFC10View();
DECLARE_DYNCREATE(CMFC10View)
public:
enum{ IDD = IDD_MFC10_FORM };
CMFC10Set* m_pSet;
// 特性
public:
CMFC10Doc* GetDocument() const;
// 操作
public:
// 重写
public:
virtual CRecordset* OnGetRecordset();
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
virtual void OnInitialUpdate(); // 构造后第一次调用
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
// 实现
public:
virtual ~CMFC10View();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// 生成的消息映射函数
protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnRecordFirst();
afx_msg void OnRecordLast();
afx_msg void OnRecordNext();
afx_msg void OnRecordPrev();
afx_msg void OnBnClickedButton1();
afx_msg void OnClickedTagnames();
CString m_strSel;
CString m_filter;
void Query();
afx_msg void OnBnClickedButton2();
};
#ifndef _DEBUG // MFC10View.cpp 中的调试版本
inline CMFC10Doc* CMFC10View::GetDocument() const
{ return reinterpret_cast<CMFC10Doc*>(m_pDocument); }
#endif
CPP文件
// MFC10View.cpp : CMFC10View 类的实现
//
#include "stdafx.h"
// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义,并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "MFC10.h"
#endif
#include "MFC10Set.h"
#include "MFC10Doc.h"
#include "MFC10View.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#include "resource.h"
#include "DevicesTable.h"
// CMFC10View
IMPLEMENT_DYNCREATE(CMFC10View, CRecordView)
BEGIN_MESSAGE_MAP(CMFC10View, CRecordView)
// 标准打印命令
ON_COMMAND(ID_FILE_PRINT, &CRecordView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, &CRecordView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CRecordView::OnFilePrintPreview)
ON_COMMAND(ID_RECORD_FIRST, &CMFC10View::OnRecordFirst)
ON_COMMAND(ID_RECORD_LAST, &CMFC10View::OnRecordLast)
ON_COMMAND(ID_RECORD_NEXT, &CMFC10View::OnRecordNext)
ON_COMMAND(ID_RECORD_PREV, &CMFC10View::OnRecordPrev)
ON_BN_CLICKED(IDC_BUTTON1, &CMFC10View::OnBnClickedButton1)
ON_BN_CLICKED(IDC_TagNames, &CMFC10View::OnClickedTagnames)
ON_BN_CLICKED(IDC_KKSCode, &CMFC10View::OnClickedTagnames)
ON_BN_CLICKED(IDC_Descriptors, &CMFC10View::OnClickedTagnames)
ON_BN_CLICKED(IDC_PointType, &CMFC10View::OnClickedTagnames)
ON_BN_CLICKED(IDC_BUTTON2, &CMFC10View::OnBnClickedButton2)
END_MESSAGE_MAP()
// CMFC10View 构造/析构
CMFC10View::CMFC10View()
: CRecordView(CMFC10View::IDD)
, m_filter(_T(""))
{
m_pSet = NULL;
// TODO: 在此处添加构造代码
}
CMFC10View::~CMFC10View()
{
}
void CMFC10View::DoDataExchange(CDataExchange* pDX)
{
CRecordView::DoDataExchange(pDX);
// 可以在此处插入 DDX_Field* 函数以将控件“连接”到数据库字段,例如
// DDX_FieldText(pDX, IDC_MYEDITBOX, m_pSet->m_szColumn1, m_pSet);
// DDX_FieldCheck(pDX, IDC_MYCHECKBOX, m_pSet->m_bColumn2, m_pSet);
// 有关详细信息,请参阅 MSDN 和 ODBC 示例
DDX_FieldText(pDX, IDC_EDIT1, (CString)m_pSet->m_TagNames, m_pSet);
DDX_FieldText(pDX, IDC_EDIT2, (CString)m_pSet->m_KKSCode, m_pSet);
DDX_FieldText(pDX, IDC_EDIT3, (CString)m_pSet->m_Descriptors, m_pSet);
DDX_FieldText(pDX, IDC_EDIT4, (CString)m_pSet->m_PointType, m_pSet);
// DDX_Radio(pDX, IDC_TagNames, m_select);
DDX_Text(pDX, IDC_FILTER, m_filter);
}
BOOL CMFC10View::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式
return CRecordView::PreCreateWindow(cs);
}
void CMFC10View::OnInitialUpdate()
{
m_pSet = &GetDocument()->m_MFC10Set;
CheckRadioButton(IDC_TagNames,IDC_PointType,IDC_TagNames);
m_strSel="TagNames";
CRecordView::OnInitialUpdate();
}
void CMFC10View::Query()
{
// 默认准备
m_pSet->m_strSort=m_strSel;
if(m_filter!="")
m_pSet->m_strFilter=m_strSel+"="+m_filter;
m_pSet->Requery();
OnRecordFirst();
}
// CMFC10View 打印
BOOL CMFC10View::OnPreparePrinting(CPrintInfo* pInfo)
{
// 默认准备
return DoPreparePrinting(pInfo);
}
void CMFC10View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 添加额外的打印前进行的初始化过程
}
void CMFC10View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 添加打印后进行的清理过程
}
// CMFC10View 诊断
#ifdef _DEBUG
void CMFC10View::AssertValid() const
{
CRecordView::AssertValid();
}
void CMFC10View::Dump(CDumpContext& dc) const
{
CRecordView::Dump(dc);
}
CMFC10Doc* CMFC10View::GetDocument() const // 非调试版本是内联的
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMFC10Doc)));
return (CMFC10Doc*)m_pDocument;
}
#endif //_DEBUG
// CMFC10View 数据库支持
CRecordset* CMFC10View::OnGetRecordset()
{
return m_pSet;
}
// CMFC10View 消息处理程序
void CMFC10View::OnRecordFirst()
{
// TODO: 在此添加命令处理程序代码
if(m_pSet->IsOpen())
{
m_pSet->MoveFirst();
this->UpdateData(false);
}
}
void CMFC10View::OnRecordLast()
{
// TODO: 在此添加命令处理程序代码
if(m_pSet->IsOpen())
{
m_pSet->MoveLast();
this->UpdateData(false);
}
}
void CMFC10View::OnRecordNext()
{
// TODO: 在此添加命令处理程序代码
if(m_pSet->IsOpen())
{
m_pSet->MoveNext();
this->UpdateData(false);
}
}
void CMFC10View::OnRecordPrev()
{
// TODO: 在此添加命令处理程序代码
if(m_pSet->IsOpen())
{
m_pSet->MovePrev();
this->UpdateData(false);
}
}
void CMFC10View::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
Query();
}
void CMFC10View::OnClickedTagnames()
{
// TODO: 在此添加控件通知处理程序代码
if(IsDlgButtonChecked(IDC_TagNames))
m_strSel="TagNames";
if(IsDlgButtonChecked(IDC_KKSCode))
m_strSel="KKSCode";
if(IsDlgButtonChecked(IDC_Descriptors))
m_strSel="Descriptors";
if(IsDlgButtonChecked(IDC_PointType))
m_strSel="PointType";
}
void CMFC10View::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
Query();
}
结论:
1、MFC ODBC使用起来比较简单,很容易就可以完成数据库类的生成,捆绑的数据表为CRecordSet的派生类(自动生成),并且嵌在文档类中:
对数据库中指定表的操作就是通过该对象来完成(增删查改),示例中视图通过获取文档类指针来获得记录集对象:
2、MFC ODBC创建工程时只能添加一张表,生成对应的记录集类(选择多张表会合并成一个类,很明显不对)。如果需要对数据库中多张表格的操作,可以通过类向导中选择添加ODBC类:
注意使用的时候需要先Open:
CDevicesTable devSet; //新增的另外一张表
devSet.Open();
devSet.Requery();
devSet.MoveFirst();
3、可以用表生成对应的集合类,也可以用视图生成(解决左右连接等跨表查询等);
4、可以利用代码动态生成DSN(否则在其他电脑上运行程序需要手动先创建DSN);
5、很显然,MFC ODBC只适用于比较简单是数据库操作,复杂的数据库操作实现起来并不容易。