资源描述
数据库实验三实验过程修改版3
———————————————————————————————— 作者:
———————————————————————————————— 日期:
40
个人收集整理 勿做商业用途
Last modified by 30 date12.22
数据库实验三实现过程详解
MFC 提供了对数据库程序设计的强大支持。对于数据库的访问,MFC 提供了两组类: ODBC(Open Database Connectivity)和 ADO(ActiveX Data Objects)。利用这两组功能强大 的类,用户可以方便的开发出基于 ODBC 或 ADO 的数据库应用。
本实验主要是通过 MFC 对前两次实验中所建数据库表的一些基本操作。此处举的例子 是对数据库中 student 表的操作,该表中包含 student 的一些基本信息,如学号、姓名、性别、 年龄。而基本操作包括添加、查找、修改以及删除。同学们也可自己进行扩展,比如增加学 生信息以及增加一些对表的操作。
1 ODBC 基础
本部分主要介绍 MFC 的一组类 ODBC。ODBC 是微软公司开放式服务结构中有关数据 库的已组成部分,它建立了一组规范,并提供了一组对数据库访问的标准 API。这些 API 函数利用 SQL 来完成其大部分任务。ODBC 本身也提供了对 SQL 语言的支持。
所谓的 ODBC 是利用微软提供的驱动程序来连接用户程序和数据库管理系统。一个基 于 ODBC 的应用程序读数据库的操作不依赖任何 DBMS,也就是说利用 ODBC 封装了对数 据库管理系统的各种操作。应用程序只要对 ODBC 进行操作,然后 ODBC 进行数据库管理 系统的操作。
在 ODBC 应用程序中,应用程序要访问一个数据库,首先必须用 ODBC 管理器注册一 个数据源,建立起 ODBC 与具体数据库的联系.只有在建立了连接之后才可以进行对数据 源的操作,进而操作数据库。下面是注册数据源的一般操作:
1) 建立数据库;
注:S表的SNO SNAME SAGE SDEPT 一定都要是char()类型!
2) 在 Windows XP 环境下打开“控制面板",单击“管理工具"图标,如下图。
图 1 管理工具选项
3) 双击“数据源"图标,弹出 ODBC 数据源管理器对话框,如下图.
图 2 ODBC 数据与管理器对话框
4) 在“ODBC 数据源管理器”对话框中,单击“添加"按钮,弹出创建新数据源对话框, 此处选择 SQL SERVER 为数据源驱动程序,如下图。
图 3 创建新数据源对话框
5) 单击“完成”按钮后,弹出创建到 SQL SERVER 的新的数据源.如下图.
图 4 创建到 SQL SERVER 的新数据源对话框
6) 在创建到 SQL Server 的新数据源对话框中按要求填写,如服务器,填写你机器上实际 的数据库服务器名,单击下一步,接下来差不多都按默认的或说明填写即可,如下列 图所示。
图 5 选择登录方式
图 6 设置默认数据库
图 7 配置数据库显示及安全相关选项
2 ODBC 数据库编程
图 8 最终查看 ODBC 数据源管理器
在 ODBC 驱动程序支持下,应用程序对数据库的访问可以方便的利用 ODBC 类来 进行。
MFC 的 ODBC 类对较复杂的 ODBC API 函数进行了封装,提供了简化的调用接口, 从而大大方便了数据库应用程序的开发。MFC 的 ODBC 类主要包括 Cdatabase 类、 Crecordset 类、CrecordView 类、CfieldExchange 类、CDBException 类.
下面利用前面连接好的数据源,进行编程,包括两方面:API 接口函数的编程以及
SQL 语句的编程.
2。1 创建单文档应用程序
1) 启动 Visual C++6。0,选择 File|New,弹出 New 对话框,选择 Projects 标签,然后再列 表中选中选择 MFC App Wizard[exe]选项,在“Project name”文本框中输入工程文件名
(根据需要自己确定),在“Location”中指定应用文件创建的位置,如下图所示:
图 9 创建 MFC AppWizard 应用程序
2) 单击 OK,弹出对话框 MFC App Wizard-Step1,如下图所示,选择 Single document 单选 按钮,单击 What language would you like your resourses in?下拉列表框的下三角按钮, 选择【中国】APPWZCHS。DLL 选项。
图 10 应用程序类型以及语言选择
3) 单击 NEXT,弹出 MFC App Wizard-Step2,选择 Database view without file support 单选
按钮,如下图所示:
图 11 选择数据库支持种类
4) 单击 Data Source 按钮,弹出 Database Options 对话框如下图所示,在 ODBC 的下拉列 表中选择之前的数据源.
图 12 数据源选择
5) 单击 OK,弹出 Select Database Tables 对话框,如下图所示,选择自己要链接的表(可 以选一张,也可多选).
图 13 数据库中表的选择
6) 单击 OK,单击 Next 按钮,这一步中选择文档类型为容器类型,如下图所示.
图 14 文档类型选择
7) 单击 Next,之后都是默认,单击 Finish 完成.到此初步的工程已经建好,下面进行界 面的设计。
2.2 新建界面按钮
本部分中,只是编写一个简单的界面,同学们可以根据自己所建数据库的需要来作出适 当的修改.
在项目工作窗口中选择 ResourceView 页面,双击 Menu 中的 IDD_LIANXI2_FORM,则 弹出文档模板和控件工具栏,如下图所示的界面:
图 15 主界面
对于文档模板,单击右键,选择 Properties,改变界面的风格。 如果没有弹出控件工具栏,则在工具栏的右边空白处单击右键,选择 Controls,如下图
所示,将鼠标在控件上停留一会,就会出现该控件的名称。
图 16 调出控件工具栏
在文档模板上添加所需的控件,这里添加了五个 Edit box 控件和四个 Button,和若干
Static Text.这里具体描述一下控件的简单用法:
控件的选取:可以用鼠标直接选取。首先选中所要的控件,比如 Static Text,然后移动
鼠标指针至文档模板上即可。
控件属性的修改:右键单击文档模板面上的控件,选择 Properties,单击左键,弹出 Text
Properties 对话框,如下图所示为 Static Text 的属性:
图 17 Static Text 控件的属性
General 标签中的 ID 为控件的编号,Caption 中可填写标题.在本例子中,可将 Caption 分别改为“学号”、“性别”等标题.而 Styles 标签可以选择控件的风格,根据需要可以美化 界面,不做介绍。
注:老师给的pdf是两个人做的东西的杂糅,同一控件可能却有两个以上ID名.另外S表只有 学号 姓名 年龄 专业(或者叫学历),没有性别。
这里将五个 Edit box 的 ID 分别改为 IDC_ID_EDIT、IDC_NAME_EDIT、
IDC_AGE_EDIT、、IDC_DEPT_EDIT 、IDC_CHECKNAME。如下图所示:
图 18 编辑框控件 ID 的更改
将四个按钮改的 ID 改为 IDC_ADD、IDC_MOD、IDC_DEL 、IDC_CHECK,如下图 所示来修改。
图 19 按钮控件 ID 的更改
调整各个控件的位置,如下图所示:
图 20 控件布局示意
添加新类 CRecordsetAdd:在工具栏上选择 Insert|New Class,添加一个新类 CRecordset
ADD,如下图所示:
图 21 添加新类选项
单击 OK,弹出 Database Options 对话框,如图所示,同样的选择数据源后,单击 OK
按钮,弹出 Select Database Tables 对话框,选择表,单击 OK.
图 22 数据源中表的选择
在 CRecordsetAdd 中添加四个成员变量如下所示:
注:在view—classwizard中添加
CString m_Sno; CString m_Sname; CString m_Sage; CString m_Sdept;
同时其成员函数 DoFieldExchange 如下:
注:这个函数会自动添加好,在CRecordsetAdd类下可以看到。
void CRecordsetAdd::DoFieldExchange(CFieldExchange* pFX)
{
//{{AFX_FIELD_MAP(CRecordsetAdd)
pFX—>SetFieldType(CFieldExchange::outputColumn); RFX_Text(pFX, _T("[Sno]"), m_Sno); RFX_Text(pFX, _T("[Sname]"), m_Sname); RFX_Int(pFX, _T("[Sage]"), m_Sage); RFX_Text(pFX, _T(”[Sdept]”), m_Sdept);
//}}AFX_FIELD_MAP
}
即采用了 RFX 机制实现了数据的交换.
在 CLianxi2View::DoDataExchange()函数中添加代码如下所示:
注:前三行DDX_Text代码分别对应以下三个edit box控件(如上图),在编写好相应控件的函数后会系统会自动自动添加,也可自己手工添加。
解释 ID 变量
查询学号的输入框、 IDC_CHECKNAME m_checkname
查询的输入框、 IDC_CHAXUN_EDIT m_chaxun
SQL语句的输入框 IDC_SQL_EDIT m_sql
后四行DDX_FieldText必须手工添加
分别对应四个显示学生 学号姓名年龄专业 的editbox控件。
void CLianxi2View::DoDataExchange(CDataExchange* pDX)
{
CRecordView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CLianxi2View)
DDX_Text(pDX, IDC_CHECKNAME, m_checkname);
DDX_Text(pDX, IDC_CHAXUN_EDIT, m_chaxun);
DDX_Text(pDX, IDC_SQL_EDIT, m_sql); DDX_FieldText(pDX, IDC_ID_EDIT, m_pSet- 〉m_Sno, m_pSet);
DDX_FieldText(pDX, IDC_NAME_EDIT, m_pSet-〉m_Sname, m_pSet);
DDX_FieldText(pDX, IDC_DEPT_EDIT, m_pSet->m_Sdept, m_pSet);
DDX_FieldText(pDX, IDC_AGE_EDIT, m_pSet—〉m_Sage, m_pSet);
//}}AFX_DATA_MAP
}
这样就实现了数据的显示问题。 “添加”的实现: 为了添加记录,添加一个对话框资源:
在项目工作去窗口中选择 ResourceView 页面,右键单击 Dialog 选择 Insert Dialog,则添加了 一个对话框,如下图所示:
图 23 插入新对话框
为其添加四个 Edit box,其 ID 分别为 IDC_ID、IDC_NAME、IDC_AGE 、IDC_DEPT。 同时按照前面所描述的方法为该对话框添加类 CAddNew,如下图所示:
图 24 子对话框添加控件
单击 View|MFC ClassWizard,在 Project 中选择 lianxi2,在 Class name 中选择 CAddNew, 则在下面的界面中显示对话框中的界面,选中 IDC_AGE,单击 Add Variable,弹出如图的 对话框,添加变量的名称,选择其类型.
图 25 为控件添加成员变量
同样,为其他控件添加变量,最后结果如图所示:
2.3 编写按钮成员函数
2.3.1 数据添加
图 26 控件与成员变量对应关系图
在主对话框中,即在 ResourceView 页面中,双击 IDD_LIANXI2_FORM,出现已经设 计好的主对话框后,双击添加按钮,出现对话框如下:
单击 OK,为其添加函数如下所示:图 27 添加成员函数
注:所有按钮函数成员函数均在Lianxi2View.cpp中,需要添加包含以下头文件:
#include ”AddNew.h” 这个是CAddNew类
#include ”MainFrm。h" 这个是主界面类
#include "SHUJUNew。h” 这个之后会提到的CSHUJUNew类。
注:老师所给程序居然有%d。有关AGE的所有%d都要改成%s。
void CLianxi2View::OnAdd()
{
// TODO: Add your control notification handler code here
CAddNew dlg; CString str; CString str1; CDatabase db;
if (IDOK==dlg.DoModal())
{
try
{
str1.Format("INSERT INTO S(Sno,Sname,Sage,Sdept)
values('%s',’%s',’%s’,'%s')”,dlg。m_id,dlg。m_name,dlg.m_age,dlg。m_dept);
db.Open(”学生信息");
db。ExecuteSQL(str1);
}
catch(CDBException *e)
{
AfxMessageBox(e-〉m_strError);
return;
}
str。Format("添加[%s]成功!”,dlg。m_name); MessageBox(str,NULL,MB_OK|MB_ICONINFORMATION);
}
}
2。3.2 数据删除
删除操作:
void CLianxi2View::OnDel()
{
// TODO: Add your control notification handler code here
// CAddNew dlg; CDatabase db; try
{
CString str1; CString str;
if (m_pSet->IsOpen())
{
m_pSet-〉Close();
}
str。Format("删除记录[%s]成功!",m_pSet—>m_Sname);
str1.Format("DELETE FROM S WHERE Sno=’%s’”,m_pSet—>m_Sno);
db。Open("学生信息”);
db.ExecuteSQL(str1); MessageBox(str,NULL,MB_OK|MB_ICONINFORMATION);
// MessageBox(”HELLO”);
}
catch (CDBException* e)
{
AfxMessageBox(e—>m_strError);
return;
}
}
2。3。3 数据修改
注:由程序中的sql语句可以看出,使用的时候,修改是不能改学号的
修改操作:
//////////////////
void CLianxi2View::OnMod()
{
// TODO: Add your control notification handler code here
CAddNew dlg; CString str; CString str1; CDatabase db;
if (IDOK==dlg。DoModal())
{
try{
if (m_pSet-〉IsOpen())
{
m_pSet-〉Close();
}
str1.Format(”UPDATE S SET Sname=’%s’,Sage='%s’,Sdept='%s’ WHERE Sno=’%s'",dlg。m_name,dlg.m_age,dlg.m_dept,dlg.m_id);
db。Open("学生信息");
db.ExecuteSQL(str1);
}
catch(CDBException *e)
{
AfxMessageBox(e-〉m_strError);
return;
}
str。Format(”修改[%s]成功!",dlg.m_name);
MessageBox(str,NULL,MB_OK|MB_ICONINFORMATION);
}
}
2.3。4 数据查询
查询操作:
void CLianxi2View::OnCheck()
{
// TODO: Add your control notification handler code here
// UpdateData(true);
//注:这里我updatedata函数出错,所以改用了下面三行代码,你可以试试
CString ss;
GetDlgItem(IDC_CHECKNAME)—〉 GetWindowText(ss);
m_checkname=ss;
CDatabase db;
db.Open(”学生信息");
CString str;
m_checkname。TrimLeft();
if(m_checkname.IsEmpty())
{
MessageBox(”要查询的学号不能为空! ”);
return;
}
CRecordset recset(&db);
CString strSQL;
strSQL.Format( "SELECT * FROM S WHERE SNO='%s'", m_checkname );
recset.Open(CRecordset::forwardOnly, strSQL, CRecordset::readOnly);
if(recset.IsEOF())
{
MessageBox("没有查到你要找的学生记录!");
}
else
{
CString temp1, temp2, temp4;
CString temp3;
recset.GetFieldValue("SNO", temp1);//这里的SNO的大小写要跟数据库S表里的SNO大小写完全一样
recset。GetFieldValue("SNAME", temp2);
recset。GetFieldValue(”SAGE”, temp3);
recset.GetFieldValue("SDEPT”, temp4);
m_pSet-〉m_SNO=temp1;
m_pSet->m_SNAME=temp2;
m_pSet->m_SAGE=temp3;
m_pSet-〉m_SDEPT=temp4;
GetDlgItem(IDC_ID_EDIT)—> SetWindowText(temp1);
GetDlgItem(IDC_NAME_EDIT)—> SetWindowText(temp2);
GetDlgItem(IDC_AGE_EDIT)—> SetWindowText(temp3);
GetDlgItem(IDC_DEPT_EDIT)—〉 SetWindowText(temp4);
}
//注:这里的updatedata一样被我干掉了,用了上面四行代码代替.
recset.Close();
}
2。3。5 数据库记录显示
注:这部分跳过吧,其他都弄好了再弄。如果你成功显示状态条了,告诉我咋弄的。
这段代码如果加到程序中,不仅不能完成它应该做的,还会导致其他部分出错!!
执行函数:
BOOL CLianxi2View::OnCommand(WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
CString str;
CMainFrame *pFrame=(CMainFrame*)AfxGetApp()-〉m_pMainWnd; CStatusBar*pStatus=&pFrame—〉m_wndStatusBar;
if (pStatus)
{
CRecordsetStatus rStatus;
m_pSet->GetStatus(rStatus);
str。Format(" 当 前 记 录 : %d/ 总 记 录 :
%d",1+rStatus.m_lCurrentRecord,m_pSet->GetRecordCount());
pStatus-〉SetPaneText(1,str);
}
return CRecordView::OnCommand(wParam, lParam);
}
执行结果显示
图 28 显示数据库记录
注:这里当然要先建好如上图28左下角所示的四个button控件
ID名分别为CreateTalbebutton DelNewtalbeButton AddNewtableButton ModButton。
2.3.6 新建表
2.9 表的操作函数
void CLianxi2View::OnCreateTalbebutton()
{
// TODO: Add your control notification handler code here
CDatabase db;
//if (!SQLConfigDataSource(NULL,ODBC_ADD_DSN,”SQL Server","DSN=学生信息"));
try
{
db.Open(”学生信息");
db。ExecuteSQL("CREATE TABLE TEACHERS (TeacherID CHAR(4)””,TeacherName CHAR(10)"”,Course CHAR(10))");
}
catch (CDBException* e)
{
AfxMessageBox(e—>m_strError);
return;
}
MessageBox(”新建表成功!");
}
向新表添加数据,这里像前面“添加”功能一样,需要再建一个 Dilog,并新建一个类,
CSHUJUNew,没有本质的不同。
void CLianxi2View::OnAddNewtableButton()
{
// TODO: Add your control notification handler code here
CSHUJUNew dlg; CString str; CString str1; CDatabase db;
if (IDOK==dlg.DoModal())
{
try
{
str1.Format(”INSERT INTO TEACHERS(TeacherID,TeacherName,Course)
VALUES(’%s’,'%s’,'%s’)”,dlg。m_teacherid,dlg。m_teachername,dlg。m_Course);
db。Open("学生信息");
db.ExecuteSQL(str1);
}
catch ( CDBException* e)
{
e—〉ReportError();
return;
}
MessageBox(”添加数据成功!”);
}
}
2.3。7 删除表
void CLianxi2View::OnDelNewtalbeButton()
{
// TODO: Add your control notification handler code here
CDatabase db;
try
{
db.Open(”学生信息");
db。ExecuteSQL(”DROP TABLE TEACHERS”);
}
catch(CDBException *e)
{
AfxMessageBox(e—>m_strError);
return;
}
MessageBox(”删除表成功!");
}
2。3.8 修改表
修改表操作代码:
void CLianxi2View::OnModButton()
{
// TODO: Add your control notification handler code here
CDatabase db;
try
{
db.Open(”学生信息");
db。ExecuteSQL(”ALTER TABLE TEACHERS ADD S_age INT”);
}
catch(CDBException *e)
{
AfxMessageBox(e—〉m_strError);
return;
}
MessageBox("修改表成功!”);
}
2.3.9 按钮查询
void CLianxi2View::Onchaxun()
{
// TODO: Add your control notification handler code here
UpdateData(true);
CListCtrl * list=(CListCtrl*) GetDlgItem(IDC_LIST1);//(CListCtrl&)GetListCtrl();
list—>ModifyStyle(NULL,LVS_REPORT);
list—〉SetExtendedStyle(LVS_EX_GRIDLINES|LVS_EX_FULLROWSELECT|LVS_EX
_HEADERDRAGDROP|LVS_EX_ONECLICKACTIVATE);
//list—>DeleteAllItems(); CDatabase db;
db。Open(”学生信息");
CRecordset recset(&db); list—〉DeleteAllItems(); CString sql,edit1; m_chaxun.TrimLeft();
if ( m_chaxun。IsEmpty())
{
AfxMessageBox("请输入学号、姓名、年龄或学历!”);
return;
}
sql.Format(”select * from S where (Sno='%s') or (Sname='%s') or (Sage=’%s’) or
(Sdept='%s')", m_chaxun,m_chaxun,m_chaxun,m_chaxun); recset。Open(CRecordset::forwardOnly,sql,CRecordset::readOnly); int ii;
while(!recset。IsEOF())
{
CString temp1,temp2,temp3,temp4; recset.GetFieldValue("Sno”,temp1); recset.GetFieldValue(”Sname",temp2); recset。GetFieldValue("Sage",temp3); recset.GetFieldValue(”Sdept",temp4);
ii=list—〉InsertItem(0,"");
list—〉InsertItem(ii,"");
list->SetItemText(ii,0, temp1); list—>SetItemText(ii,1, temp2); list-〉SetItemText(ii,2, temp3); list—〉SetItemText(ii,3, temp4); UpdateData(false);
ii++;
recset。MoveNext();
}
recset.Close(); MessageBox("查询成功!!!”);
db。Close();
}
2.3。10 界面执行 SQL
2。10 执行语句操作(如果为查询,并将查询结果显示到界面上)
注:这里需要先建好界面右半部分的所有控件.
控件ID名和相应变量要和之前在 CLianxi2View::DoDataExchange()函数中添加的代码相一致
SQL语句的输入框 IDC_SQL_EDIT m_sql
查询的输入框、 IDC_CHAXUN_EDIT m_chaxun
右下角的显示控件是List Control控件如右图:
添加后将其properties-———-styles—--—view改为report。如图:
执行操作语句前先初始化列表,函数操作为
注:OnInitialUpdate此函数已存在,只需改变其中的代码即可
void CLianxi2View::OnInitialUpdate()
{
m_pSet = &GetDocument()—>m_lianxi2Set; CRecordView::OnInitialUpdate(); GetParentFrame()—>RecalcLayout(); ResizeParentToFit();
while (!m_pSet—>IsEOF())
{
m_pSet-〉MoveNext();
m_pSet—〉GetRecordCount();
}
m_pSet->MoveFirst(); UpdateData(TRUE);
CListCtrl * list=(CListCtrl*) GetDlgItem(IDC_LIST1);//(CListCtrl&)GetListCtrl();
list—>ModifyStyle(NULL,LVS_REPORT);
list-〉SetExtendedStyle(LVS_EX_GRIDLINES|LVS_EX_FULLROWSELECT|LVS_EX
_HEADERDRAGDROP|LVS_EX_ONECLICKACTIVATE);
//像这种过长的语句在word只能分开在不同行,但是在程序里要写在一行里。
list—〉InsertColumn(0,”Sno");
list—>InsertColumn(1,"Sname”); list—〉InsertColumn(2,”Sage”); list-〉InsertColumn(3,”Sdept"); list—>SetColumnWidth(0,80);
list->SetColumnWidth(1,80); list->SetColumnWidth(2,80); list—>SetColumnWidth(3,80);
UpdateData(FALSE);
}
注:是m_sql不是m_sqledit
执行 SQL 执行语句:
void CLianxi2View::Onselect()
{
// TODO: Add your control notification handler code here
UpdateData(true);
CListCtrl * list=(CListCtrl*) GetDlgItem(IDC_LIST1);//(CListCtrl&)GetListCtrl();
list—>ModifyStyle(NULL,LVS_REPORT);
list->SetExtendedStyle(LVS_EX_GRIDLINES|LVS_EX_FULLROWSELECT|LVS_EX
_HEADERDRAGDROP|LVS_EX_ONECLICKACTIVATE);
list->DeleteAllItems(); CDatabase db;
db。Open("学生信息”);
CRecordset recset(&db);
list-〉DeleteAllItems();
CString sql,edit1;
m_sql。TrimLeft();
if ( m_sql。IsEmpty())
{
AfxMessageBox("请输入查询语句!");
return;
}
sql。
展开阅读全文