C++第9章 數(shù)據(jù)庫編程_第1頁
C++第9章 數(shù)據(jù)庫編程_第2頁
C++第9章 數(shù)據(jù)庫編程_第3頁
C++第9章 數(shù)據(jù)庫編程_第4頁
C++第9章 數(shù)據(jù)庫編程_第5頁
已閱讀5頁,還剩45頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

第9章

數(shù)據(jù)庫編程

(DatabaseProgramming)主講教師:劉懷廣

lhg81219@163.comVisualC++6.0為用戶提供了ODBC(開放數(shù)據(jù)庫連接)

、DAO(數(shù)據(jù)訪問對象)及OLEDB(OLE數(shù)據(jù)庫)三種數(shù)據(jù)庫方式。這三種方式中最簡單也最常用的是ODBC,因此本章先來重點介紹MFC的ODBC編程方法和技巧,然后介紹基于OLEDB的ADO(ActiveXDataObjects,ActiveX數(shù)據(jù)對象)技術,最后介紹一些用于數(shù)據(jù)庫的ActiveX控件。數(shù)據(jù)庫概述9.1MFCODBC數(shù)據(jù)庫概述ODBC是一種使用SQL的程序設計接口,使用ODBC能使用戶編寫數(shù)據(jù)庫應用程序變得容易簡單,避免了與數(shù)據(jù)源相連接的復雜性。MFC的ODBC數(shù)據(jù)庫類CDatabase(數(shù)據(jù)庫類)、CRecordSet(記錄集類)和CRecordView(記錄視圖類)可為用戶管理數(shù)據(jù)庫提供了切實可行的解決方案。9.1.1數(shù)據(jù)庫基本概念1.數(shù)據(jù)庫和數(shù)據(jù)庫管理系統(tǒng)DBMS

數(shù)據(jù)庫是指以一定的組織形式存放在計算機存儲介質(zhì)上的相互關聯(lián)的數(shù)據(jù)的集合。DBMS:包括數(shù)據(jù)庫的建立和記錄的輸入、修改、檢索、顯示、刪除和統(tǒng)計等。流行的DBMS都提供了一個SQL接口。9.1.1數(shù)據(jù)庫基本概念2.SQL(StructuredQueryLanguage)

DBMS中訪問和操作的語言,SQL(結構化查詢語言)語句分為兩類:

DDL(DataDefinitionLanguage,數(shù)據(jù)定義語言)語句,它是用來創(chuàng)建表、索引等;

DML(DataManipulationLanguage,數(shù)據(jù)操作語言)語句,這些語句是用來讀取數(shù)據(jù)、更新數(shù)據(jù)和執(zhí)行其他類似操作的語句。

DCL(DataControlLanguage,數(shù)據(jù)控制語言)包括數(shù)據(jù)庫用戶賦權,廢除用戶訪問權限,提交當前事務,中止當前事務如:GRANT,REVOKE,COMMIT,ROLLBACK9.1.2常用的SQL語句1.SELECT

select_listFROMtable_list[WHEREcondition]

如:SELECT姓名FROM學生WHERE成績>802.INSERTINTO

table_name[field_name]VALUES(expression1,expression2,..)

如:INSERTINTO學生(姓名,成績)VALUES(‘張三’,60)3.UPDATE

table_nameSETField_name1=expresion1,Field_name2=expresion2…

如:UPDATE學生SET成績=60WHERE姓名=‘張三’4.DELETE

table_name[WHEREcondition]

如:DELETE學生WHERE成績<603.ODBC、DAO和OLEDB

ODBC提供了應用程序接口(API),使得任何一個數(shù)據(jù)庫都可以通過ODBC驅(qū)動器與指定的DBMS相聯(lián)。

DAO使用Jet數(shù)據(jù)庫引擎形成一系列的數(shù)據(jù)訪問對象:數(shù)據(jù)庫對象、表和查詢對象、記錄集對象等。

OLEDB提供一個統(tǒng)一的數(shù)據(jù)訪問接口,使得應用程序可以使用同樣的方法訪問各種數(shù)據(jù),而不用考慮數(shù)據(jù)的具體存儲地點、格式或類型。9.1.1數(shù)據(jù)庫基本概念4.ADO(ActiveXDataObjects)

ADO是目前比較流行的客戶端數(shù)據(jù)庫編程技術。ADO技術基于COM(ComponentObjectModel,組件對象模型),是遠程數(shù)據(jù)存取的發(fā)展方向。9.1.1數(shù)據(jù)庫基本概念ADO是MS為最新和最強大的數(shù)據(jù)訪問接口OLEDB而設計,是一個便于使用的應用程序?qū)咏涌?。ADO是一種面向?qū)ο蟮摹⑴c語言無關的(Language_Neutral)數(shù)據(jù)訪問應用編程接口。它對OLEDBAPI進行封裝,實現(xiàn)對數(shù)據(jù)的高層訪問,同時它也提供了多語言的訪問技術,此外,由于ADO提供了訪問自動化接口,它也支持腳本語言。ADO最主要的優(yōu)點在于易于使用、速度快、內(nèi)存支出少和磁盤遺跡小。ADO是用來訪問OLEDB的數(shù)據(jù)庫技術。在模型層次上它基于OLEDB,但在應用上又高于OLEDB,因此它簡化了對對象模型的操作,并且不依賴于對象之間的相互層次關系。

ODBC數(shù)據(jù)庫應用程序(Application):用宿主語言和ODBC函數(shù)編寫的應用程序用于訪問數(shù)據(jù)庫。其主要任務是管理安裝的ODBC驅(qū)動程序和管理數(shù)據(jù)源。驅(qū)動程序管理器(DriverManager):驅(qū)動程序管理器包含在ODBC32.DLL中,對用戶是透明的。其任務是管理ODBC驅(qū)動程序,為應用程序加載、調(diào)用和卸載DB驅(qū)動程序,是ODBC中最重要的部件。DB驅(qū)動程序(DBMSDriver):是一些DLL,提供了ODBC和數(shù)據(jù)庫之間的接口。處理ODBC函數(shù),向數(shù)據(jù)源提交用戶請求執(zhí)行的SQL語句。數(shù)據(jù)源(DataSource):是DB驅(qū)動程序與DBS之間連接的命名。數(shù)據(jù)源包含了數(shù)據(jù)庫位置和數(shù)據(jù)庫類型等信息,實際上是一種數(shù)據(jù)連接的抽象。9.1.1數(shù)據(jù)庫基本概念ODBC體系9.1.2MFCODBC向?qū)н^程用MFCAppWizard使用ODBC數(shù)據(jù)庫的一般過程是:①用Access或其他數(shù)據(jù)庫工具構造一個數(shù)據(jù)庫;②在Windows中為剛才構造的數(shù)據(jù)庫定義一個ODBC數(shù)據(jù)源;③在創(chuàng)建數(shù)據(jù)庫處理的文檔應用程序向?qū)е羞x擇數(shù)據(jù)源;④設計界面,并使控件與數(shù)據(jù)表字段關聯(lián)。1.構造數(shù)據(jù)庫

數(shù)據(jù)庫表與表之間的關系構成了一個數(shù)據(jù)庫。作為示例,這里用MicrosoftAccess創(chuàng)建一個數(shù)據(jù)庫Student.mdb,其中暫包含一個數(shù)據(jù)表score,用來描述學生課程成績。在表中包括上、下兩部分,上部分是數(shù)據(jù)表的記錄內(nèi)容,下部分是數(shù)據(jù)表的結構內(nèi)容。

表9.1學生課程成績表(score)及其表結構圖8.1Windows2000的管理工具圖8.2ODBC數(shù)據(jù)源管理器2.創(chuàng)建ODBC數(shù)據(jù)源

Windows中的ODBC組件是出現(xiàn)在系統(tǒng)的“控制面板”管理工具中,如圖8.1所示。雙擊ODBC圖標(在圖8.1中已圈定),進入ODBC數(shù)據(jù)源管理器。在這里,用戶可以設置ODBC數(shù)據(jù)源的一些信息。其中,“用戶DSN”頁面是用來定義用戶自己在本地計算機使用的數(shù)據(jù)源名(DSN),如圖8.2所示。圖8.3“創(chuàng)建新數(shù)據(jù)源”對話框

圖8.4ODBCAccess安裝對話框

創(chuàng)建用戶DSN的過程如下:(1)單擊[添加]→彈出“創(chuàng)建新數(shù)據(jù)源”→選擇“MicrosoftAccessDriver”。(2)單擊[完成]→進入指定驅(qū)動程序的安裝對話框→單擊[選擇]將前面創(chuàng)建的數(shù)據(jù)庫調(diào)入→在數(shù)據(jù)源名輸入“DatabaseExampleForVC++”,結果如圖8.4所示。(3)單擊[確定]按鈕,剛才創(chuàng)建的用戶數(shù)據(jù)源被添加在“ODBC數(shù)據(jù)源管理器”的“用戶數(shù)據(jù)源”列表中。如圖8.5所示。圖8.5用戶數(shù)據(jù)源列表9.1.2MFCODBC向?qū)н^程9.1.2MFCODBC向?qū)н^程表9.2MFC支持數(shù)據(jù)庫的不同選項3.在MFCAppWizard中選擇數(shù)據(jù)源1)創(chuàng)建一個支持數(shù)據(jù)庫的文檔應用程序Ex_ODBC。2)在向?qū)У牡?步對話框中加入數(shù)據(jù)庫的支持。其中各選項的含義如表9.2所示。3)選中“數(shù)據(jù)庫查看使用文件支持”項,單擊[DataSource]按鈕,彈出“DatabaseOptions”對話框,從中選擇ODBC的數(shù)據(jù)源“DatabaseExampleForVC++”,如圖9.7所示。圖9.7“DatabaseOptions”對話框

9.1.2MFCODBC向?qū)н^程(4)保留其他默認選項,單擊[OK]按鈕,彈出“SelectDatabaseTables”對話框,從中選擇要使用的表score。(5)單擊[OK]按鈕,又回到了向?qū)У牡?步對話框。(6)單擊[完成]按鈕。開發(fā)環(huán)境自動打開表單視圖CEx_ODBCView的對話框資源模板IDD_EX_ODBC_FORM以及相應的對話框編輯器。(7)編譯并運行,結果如圖8.9所示。記錄瀏覽按鈕圖8.9Ex_ODBC運行結果9.1.2MFCODBC向?qū)н^程4.設計瀏覽記錄界面在上面的Ex_ODBC中,MFC為用戶自動創(chuàng)建了用于瀏覽數(shù)據(jù)表記錄的工具按鈕和相應的“記錄”菜單項。若在表單視圖CEx_ODBCView中添加控件并與表的字段相關聯(lián),就可以根據(jù)表的當前記錄位置顯示相應的數(shù)據(jù)。其步驟如下。(1)按照圖所示的布局,為表單對話框資源模板添加控件。9.1.2MFCODBC向?qū)н^程表8.3表單對話框控件及屬性(2)按快捷鍵Ctrl+W→切換到MemberVariables頁面→為上述控件添加相關聯(lián)的數(shù)據(jù)成員。與以往添加控件變量不同的是,這里添加的控件變量都是由系統(tǒng)自動定義的,并與數(shù)據(jù)庫表字段相關聯(lián)的。9.1.2MFCODBC向?qū)н^程表8.4控件變量(3)按照上一步驟的方法,為表8.4所示的其他控件依次添加相關聯(lián)的成員變量。需要說明的是,控件變量的范圍和大小應與數(shù)據(jù)表中的字段一一對應。(4)編譯運行并測試。9.1.2MFCODBC向?qū)н^程9.1.3ODBC數(shù)據(jù)表綁定更新圖8.14“MFCClassWizard”(1)按快捷鍵Ctrl+W,切換到“MemberVariables”頁面。(2)在“Classname”的下拉列表中選擇“CEx_ODBCSet”,[UpdateColumns]和[BindAll]按鈕被激活,如圖8.14所示。圖8.15“DatabaseOptions”

圖8.16“SelectDatabaseTables”(3)[UpdateColumns]按鈕,彈出“DatabaseOptions”對話框,選擇ODBC數(shù)據(jù)源“DatabaseExampleForVC++”,如圖8.15所示。(4)單擊[OK],如圖8.16的“SelectDatabaseTables”,選擇要使用的表。9.1.3ODBC數(shù)據(jù)表綁定更新(5)單擊[OK],又回到MFCClassWizard界面。(6)單擊[BindAll]按鈕,MFCWizard將自動為字段落添加相關聯(lián)的變量。9.1.3ODBC數(shù)據(jù)表綁定更新9.2MFCODBC應用編程

使用MFC所供的ODBC類:CDatabase(數(shù)據(jù)庫類)、CRecordSet(記錄集類)和CRecordView(可視記錄集類)。

CDatabase類:提供對數(shù)據(jù)源的連接,通過它可以對數(shù)據(jù)源進行操作;

CRecordSet類:為用戶提供了對表記錄進行操作的許多功能,如查詢記錄、添加記錄、刪除記錄、修改記錄等。

CRecordView類:控制并顯示數(shù)據(jù)庫記錄,該視圖是直接連到一個CRecordSet對象的表單視圖。9.2MFCODBC介紹MFCODBC是MFC對ODBC進行的封裝,以簡化對ODBCAPI的

調(diào)用,從而實現(xiàn)面向?qū)ο蟮臄?shù)據(jù)庫編程接口.MFCODBC的封裝主要開發(fā)了CDatabase類和CRecordSet類

CDatabase類

CDatabase類用于應用程序建立同數(shù)據(jù)源的連接。CDatabase類中包含一個m_hdbc變量,它代表了數(shù)據(jù)源的連接句柄。如果要建立CDatabase類的實例,應先調(diào)用該類的構造函數(shù),再調(diào)用Open函數(shù),通過調(diào)用,初始化環(huán)境變量,并執(zhí)行與數(shù)據(jù)源的連接。在通過Close函數(shù)關閉數(shù)據(jù)源。

CDatabase類提供了對數(shù)據(jù)庫進行操作的函數(shù)及事務操作。

CRecordSet類

CRecordSet類定義了從數(shù)據(jù)庫接收或者發(fā)送數(shù)據(jù)到數(shù)據(jù)庫的成員變量,以實現(xiàn)對數(shù)據(jù)集的數(shù)據(jù)操作。

CRecordSet類的成員變量m_hstmt代表了定義該記錄集的SQL語句句柄,m_nFields為記錄集中字段的個數(shù),m_nParams為記錄集所使用的參數(shù)個數(shù)。

CRecordSet的記錄集通過CDatabase實例的指針實現(xiàn)同數(shù)據(jù)源的連接,即CRecordSet的成員變量m_pDatabase.

MFCODBC編程更適合于界面型數(shù)據(jù)庫應用程序的開發(fā),但由于CDatabase類和CRecordSet類提供的數(shù)據(jù)庫操作函數(shù)有限,支持的游標類型也有限,限制了高效的數(shù)據(jù)庫開發(fā)。在編程層次上屬于高級編程。

9.2.1查詢記錄圖8.18要添加的控件

CRecordSet類的成員變量m_strFilter、m_strSort和成員函數(shù)Open可以對表進行記錄的查詢和排序。在前面的Ex_ODBC的表單中添加一個編輯框和一個[查詢]按鈕:單擊[查詢]按鈕,將按編輯框中的學號內(nèi)容對數(shù)據(jù)表進行查詢,并將查找到的記錄顯示在前面添加的控件中。具體過程如下:(1)打開Ex_ODBC應用程序的表單資源,按圖8.18所示的布局:添加編輯框ID為IDC_EDIT_QUERY,“查詢”按鈕ID為IDC_BUTTON_QUERY。9.2.1查詢記錄(2)用MFCClassWizard為控件IDC_EDIT_QUERY添加Cstring型的成員變量m_strQuery。(3)在CEx_ODBCView類中添加按鈕控件IDC_BUTTON_QUERY的BN_CLICKED消息映射,并在映射函數(shù)中添加下列代碼:(4)編譯運行并測試,結果如圖所示。圖8.19查詢記錄voidCEx_ODBCView::OnButtonQuery(){ UpdateData();

m_strQuery.TrimLeft();//刪除字符串左邊的空格及控制字符如(\n\t空格等)

if(m_strQuery.IsEmpty()){MessageBox("要查詢的學號不能為空!");return;} if(m_pSet->IsOpen())m_pSet->Close();//如果記錄集打開,則先關閉

m_pSet->m_strFilter.Format("studentno='%s'",m_strQuery);

//studentno是score表的字段名,用來指定查詢條件

m_pSet->m_strSort="course";

//course是score表的字段名,用來按course字段從小到大排序

m_pSet->Open();//打開記錄集

if(!m_pSet->IsEOF())//如果打開記錄集有記錄

UpdateData(FALSE);//自動更新表單中控件顯示的內(nèi)容

else MessageBox("沒有查到你要找的學號記錄!");}

m_strFilter和m_strSort是CRecordSet的成員變量,用來執(zhí)行條件查詢和結果排序。其中,m_strFilter稱為“過濾字符串”,相當于SQL語句中WHERE后的條件串;而m_strSort稱為“排序字符串”,相當于SQL語句中ORDERBY后的字符串。若字段的數(shù)據(jù)類型是文本,則需要在m_strFilter字符串中將單引號將查詢的內(nèi)容括起來,對于數(shù)字,則不需要用單引號。9.2.1查詢記錄9.2.2編輯記錄m_pSet->AddNew(); //在表的末尾增加新記錄m_pSet->SetFieldNull(&(m_pSet->m_studentno),FALSE);//設定m_studentno值不為空(NULL)m_pSet->m_studentno="21010503"; //輸入新的字段值m_pSet->Update(); //將新記錄存入數(shù)據(jù)庫m_pSet->Requery(); //刷新記錄集,這在快照集方式下是必須的

CRecordSet類為用戶提供了成員函數(shù)用來添加記錄、刪除記錄和修改記錄等。1.增加記錄使用AddNew函數(shù),但要求數(shù)據(jù)庫必須是以“可增加”的方式打開的。9.2.2編輯記錄2.刪除記錄直接使用CRecordSet::Delete刪除記錄。要使操作有效,還需要移動記錄函數(shù)CRecordsetStatus

status;m_pSet->GetStatus(status);//獲取當前記錄集狀態(tài)m_pSet->Delete(); //刪除當前記錄if(status.m_lCurrentRecord==0)

m_pSet->MoveNext(); //若當前記錄索引號為0(0表示第一條記錄) //則下移一個記錄else

m_pSet->MoveFirst(); //移動到第一個記錄處UpdateData(FALSE);3.修改記錄函數(shù)CRecordSet::Edit可以用來修改記錄,例如:m_pSet->Edit(); //修改當前記錄m_pSet->m_name=“杰克遜"; //修改當前記錄字段值m_pSet->Update(); //將修改結果存入數(shù)據(jù)庫m_pSet->Requery();9.2.2編輯記錄4.撤消操作如果用戶在進行增加或者修改記錄后,希望放棄當前操作,則在調(diào)用CRecordSet::Update()函數(shù)之前調(diào)用CRecordSet::Move(AFX_MOVE_REFRESH)來撤消操作,便可恢復在增加或修改操作之前的當前記錄。9.2.2編輯記錄9.2.3字段操作

CRecordSet類中的成員變量m_nFields

:用于保存數(shù)據(jù)表的字段個數(shù)。成員函數(shù)GetODBCFieldInfo及GetFieldValue可以簡化多字段的訪問操作。voidGetODBCFieldInfo(shortnIndex,CODBCFieldInfo&fieldinfo);

nIndex:指定字段索引號,0表示第一個字段,1表示第二個字段,以此類推。

fieldinfo是CODBCFieldInfo結構參數(shù),用來表示字段信息。9.2.3字段操作struct

CODBCFieldInfo{

CString

m_strName; //字段名

SWORDm_nSQLType;//字段的SQL數(shù)據(jù)類型

UDWORDm_nPrecision;//字段的文本大小或數(shù)據(jù)大小

SWORDm_nScale; //字段的小數(shù)點位數(shù)

SWORDm_nNullability;//字段接受空值(NULL)能力};9.2.3字段操作struct

CRecordsetStatus{longm_lCurrentRecord; //當前記錄的索引,0表示第一個記錄,1表示第二個記錄,依次類推。但-1表示在第一個記錄之前,-2表示不確定。

BOOLm_bRecordCountFinal; //記錄總數(shù)是否是最終結果};voidGetFieldValue(shortnIndex,CString&strValue);nIndex:指定字段索引號,strValue:返回字段的內(nèi)容。longGetRecordCount()const;//獲得表中的記錄總數(shù)voidGetStatus(CRecordsetStatus&rStatus)const;//當前記錄的索引表9.8課程信息表(course)及其表結構[例Ex_Field]字段的編程操作1.為Student.mdb添加一個數(shù)據(jù)表course:用MicrosoftAccess為數(shù)據(jù)庫Student.mdb添加一個數(shù)據(jù)表course,如表9.8所示。表中上部分是數(shù)據(jù)表的記錄內(nèi)容,下部分是數(shù)據(jù)表的結構內(nèi)容。#ifndef_AFX_NO_AFXCMN_SUPPORT#include<afxcmn.h>//MFCsupportforWindowsCommonControls#endif//_AFX_NO_AFXCMN_SUPPORT#include<afxdb.h>2.文檔程序添加ODBC的支持(1)創(chuàng)建一個默認的單文檔應用程序Ex_Field,但在向?qū)У牡?步將CEx_FieldView的基類由默認的CView選擇為CListView類。(2)將項目工作區(qū)窗口切換到FileView頁面,展開HeaderFiles所有項,雙擊stdafx.h,打開該文件。(3)在stdafx.h中添加ODBC數(shù)據(jù)庫支持的頭文件包含#include<afxdb.h>:3.創(chuàng)建數(shù)據(jù)表score的CRecordSet派生類(1)按快捷鍵Ctrl+W→單擊[AddClass],從彈出的下拉菜單中選擇“New”。(2)在彈出的“AddClass”對話框中指定CRecordSet的派生類CCourseSet。圖8.23定義新的CRecordSet派生類(3)單擊[OK],彈出“DatabaseOptions”。從中選擇ODBC的數(shù)據(jù)源“DatabaseExampleForVC++”,單擊[OK],彈出“SelectDatabaseTables”對話框,從中選擇要使用的表course。(4)單擊[OK]回到MFCClassWizard界面,單擊[確定],系統(tǒng)自動為用戶生成CCourseSet類所需要的代碼。(5)在CEx_FieldView::PreCreateWindow函數(shù)中添加修改列表視圖風格的代碼:BOOLCEx_FieldView::PreCreateWindow(CREATESTRUCT&cs){

cs.style&=~LVS_TYPEMASK;

cs.style|=LVS_REPORT;//報表方式

returnCListView::PreCreateWindow(cs);}(6)在CEx_FieldView::OnInitialUpdate函數(shù)中添加下列代碼:voidCEx_FieldView::OnInitialUpdate(){

CListView::OnInitialUpdate();

CListCtrl&m_ListCtrl=GetListCtrl();//獲取內(nèi)嵌在列表視圖中的列表控件

CCourseSet

cSet;

cSet.Open(); //打開記錄集

CODBCFieldInfofield;

//創(chuàng)建列表頭

for(UINTi=0;i<cSet.m_nFields;i++) { cSet.GetODBCFieldInfo(i,field); m_ListCtrl.InsertColumn(i,field.m_strName,LVCFMT_LEFT,100); }//添加列表項

int

nItem=0;

CString

str; while(!cSet.IsEOF()) {for(UINTi=0;i<cSet.m_nFields;i++){cSet.GetFieldValue(i,str); if(i==0)m_ListCtrl.InsertItem(nItem,str); else m_ListCtrl.SetItemText(nItem,i,str); }

nItem++;

cSet.MoveNext(); }

cSet.Close(); //關閉記錄集}(7)在Ex_FieldView.cpp文件的前面添加CCourseSet類的頭文件包含:

#include"Ex_FieldDoc.h"#include"Ex_FieldView.h"#include"CourseSet.h"(8)編譯運行,結果如圖9.22所示。圖9.22Ex_Field第一次運行結果4.在狀態(tài)欄中顯示當前記錄號和記錄總數(shù)(1)在MainFrm.cpp文件中,向原來的indicators數(shù)組添加一個元素,用來在狀態(tài)欄上增加一個窗格:staticUINTindicators[]={ID_SEPARATOR,//第一個信息行窗格

ID_SEPARATOR,//第二個信息行窗格

ID_INDICATOR_CAPS,ID_INDICATOR_NUM,ID_INDICATOR_SCRL,};voidDispRecNum(CCourseSet*pSet){ CString

str;

CMainFrame*pFrame=(CMainFrame*)AfxGetApp()->m_pMainWnd;//獲得主框架窗口的指針

CStatusBar*pStatus=&pFrame->m_wndStatusBar;//獲得主框架窗口中的狀態(tài)欄指針

if(pStatus){ CRecordsetStatus

rStatus;

pSet->GetStatus(rStatus);//獲得當前記錄信息

str.Format("當前記錄:%d總記錄:%d",1+rStatus.m_lCurrentRecord,pSet->GetRecordCount());

pStatus->SetPaneText(1,str); //更新第二個窗格的文本

}}//該函數(shù)先獲得狀態(tài)欄對象的指針,然后調(diào)用SetPaneText函數(shù)更新第二個窗格文本(2)在Ex_FieldView.cpp文件的前面添加一個全局函數(shù)DispRecNum成員函數(shù)(3)在CEx_ODBCView的OnInitialUpdate函數(shù)處添加下列代碼:voidCEx_FieldView::OnInitialUpdate(){…

CString

str;while(!cSet.IsEOF()) {… }::DispRecNum(&cSet);

cSet.Close(); //關閉記錄集}(4)在Ex_ODBCView.cpp文件的開始處增加下列語句:

#include"Ex_FieldDoc.h" #include"Ex_FieldView.h" #include"CourseSet.h" #include"MainFrm.h"(5)將MainFrm.h文件中的保護型變量m_wndStatusBar變成公共變量。(6)編譯運行并測試,結果如圖8.25所示。顯示的記錄信息圖8.25Ex_Field最后運行結果9.2.4多表處理圖9.24Ex_Student運行結果

下面的示例在一個對話框中用兩個控件來進行學生課程成績信息的相關操作,如圖9.24所示,左邊是樹視圖,用來顯示學生成績、專業(yè)和班級號三個層次信息,單擊班級號,所有該班級的學生課程成績信息將在右邊的列表視圖中顯示出來。[例Ex_Student]多表處理1.為數(shù)據(jù)庫Student.mdb添加一個數(shù)據(jù)表student用MicrosoftAccess為數(shù)據(jù)庫Student.mdb添加一個數(shù)據(jù)表student,如表8.6所示。表中上部分是數(shù)據(jù)表的記錄內(nèi)容,下部分是數(shù)據(jù)表的結構內(nèi)容。表8.6學生基本信息表(student)及其表結構2.創(chuàng)建并設計對話框應用程序(1)創(chuàng)建一個默認的基于對話框應用程序Ex_Student。(2)刪除[取消]按鈕和默認的靜態(tài)文本控件。(3)對話框的標題改為“處理多表”,將[確定]按鈕的標題文本改為“退出”。(4)參看圖8.26,添加一個樹控件,在其屬性對話框中,選中“有按鈕”、“有行(Lines,線)”、“Linesatroot”和“總是顯示選擇”屬性。(5)添加一個列表控件,在其屬性對話框中,將“查看”屬性選為“Report”。(6)用MFCClassWizard在CEx_StudentDlg類中,添加樹控件的控件變量為m_treeCtrl,添加列表控件的控件變量為m_listCtrl。3.添加對MFCODBC的支持及記錄集在stdafx.h文件中添加ODBC數(shù)據(jù)庫支持的頭文件包含

#include<afxdb.h>

用MFCClassWizard為數(shù)據(jù)表student、course和score分別創(chuàng)建CRecordSet派生類CStudentSet、CCourseSet和CScoreSet。4.完善左邊樹控件的代碼(1)為CEx_StudentDlg類添加一個成員函數(shù)FindTreeItem,用來查找指定節(jié)點下是否有指定節(jié)點文本的子節(jié)點,該函數(shù)的代碼如下:HTREEITEMCEx_StudentDlg::FindTreeItem(HTREEITEM

hParent,CString

str){HTREEITEMhNext;

CString

strItem;

hNext=m_treeCtrl.GetChildItem(hParent);while(hNext!=NULL){strItem=m_treeCtrl.GetItemText(hNext);if(strItem==str)returnhNext;elsehNext=m_treeCtrl.GetNextItem(hNext,TVGN_NEXT);}returnNULL;}(2)為CEx_StudentDlg類添加CImageList成員變量m_ImageList。(3)在CEx_StudentDlg::OnInitDialog中添加下列代碼:BOOLCEx_StudentDlg::OnInitDialog(){…

SetIcon(m_hIcon,FALSE); //Setsmalliconm_ImageList.Create(16,16,ILC_COLOR8|ILC_MASK,2,1);

m_treeCtrl.SetImageList(&m_ImageList,TVSIL_NORMAL);SHFILEINFOfi; //定義一個文件信息結構變量

SHGetFileInfo("C:\\Windows",0,&fi,sizeof(SHFILEINFO), SHGFI_ICON|SHGFI_SMALLICON);//獲取文件夾圖標

m_ImageList.Add(fi.hIcon);//獲取打開文件夾圖標

SHGetFileInfo("C:\\Windows",0,&fi,sizeof(SHFILEINFO),HGFI_ICON|SHGFI_SMALLICON|SHGFI_OPENICON);m_ImageList.Add(fi.hIcon);HTREEITEMhRoot,hSpec,hClass;

hRoot=m_treeCtrl.InsertItem("學生成績",0,1);

CStudentSet

sSet;

sSet.m_strSort=“special”; //按專業(yè)排序

sSet.Open(); while(!sSet.IsEOF()){

hSpec=FindTreeItem(hRoot,sSet.m_special);//查找是否有重復的專業(yè)節(jié)點

if(hSpec==NULL)//若沒有重復的專業(yè)節(jié)點

hSpec=m_treeCtrl.InsertItem(sSet.m_special,0,1,hRoot);

hClass=FindTreeItem(hSpec,sSet.m_studentno.Left(6)); //查找是否有重復的班級節(jié)點

if(hClass==NULL)//若沒有重復的班級節(jié)點

hClass=m_treeCtrl.InsertItem(sSet.m_studentno.Left(6),0,1,hSpec);

sSet.MoveNext(); }

sSet.Close(); returnTRUE;//returnTRUEunlessyousetthefocustoacontrol}(4)在Ex_StudentDlg.cpp文件的前面添加記錄集類的包含文件:

#include"Ex_StudentDlg.h"#include"StudentSet.h"#include"ScoreSet.h"#include"CourseSet.h"(5)編譯運行,結果如圖8.27所示。圖8.27Ex_Student第一次運行結果5.完善右邊列表控件的代碼(1)在CEx_StudentDlg::OnInitDialog函數(shù)中添加代碼,創(chuàng)建列表標題頭BOOLCEx_StudentDlg::OnInitDialog(){…

sSet.Close();//設置列表頭

CString

strHeader[]={"學號","姓名","課程號","課程所屬專業(yè)", "課程名稱","課程類別","開課學期","課時數(shù)","學分","成績"};

int

nLong[]={80,80,80,180,180,80,80,80,80,80};for(int

nCol=0;nCol<sizeof(strHeader)/sizeof(CString);nCol++)

m_listCtrl.InsertColumn(nCol,strHeader[nCol],LVCFMT_LEFT,nLong[nCol]);returnTRUE;//returnTRUEunlessyousetthefocustoacontrol}(2)為CEx_StudentDlg類添加一個成員函數(shù)DispScoreAndCourseInfo,用來根據(jù)指定的條件在列表控件中用報表形式顯示學生成績的所有信息。voidCEx_StudentDlg::DispScoreAndCourseInfo(CString

strFilter){ m_listCtrl.DeleteAllItems();//刪除所有的列表項

CScoreSet

sSet;

sSet.m_strFilter=strFilter;//設置過濾條件

sSet.Open(); //打開score表

int

nItem=0;

CString

str; while(!sSet.IsEOF()) {m_listCtrl.InsertItem(nItem,sSet.m_studentno);//插入學號

//根據(jù)score表中的studentno(學號)獲取student表中的"姓名"

CStudentSet

uSet;

uSet.m_strFilter.Format("studentno='%s'",sSet.m_studentno);

uSet.Open(); if(!uSet.IsEOF())m_listCtrl.SetItemText(nItem,1,uSet.m_studentname);

uSet.Close();

m_listCtrl.SetItemText(nItem,2,sSet.m_course);

//根據(jù)score表中的course(課程號)獲取course表中的課程信息

CCourseSet

cSet;

cSet.m_strFilter.Format("courseno='%s'",sSet.m_course);

cSet.Open(); UINTi=7; if(!cSet.IsEOF()){for(i=1;i<cSet.m_nFields;i++){cSet.GetFieldValue(i,str);//獲取指定字段值

m_listCtrl.SetItemText(nItem,i+2,str); } }

cSet.Close(); str.Format("%0.1f",sSet.m_score);

m_listCtrl.SetItemText(nItem,i+2,str);

sSet.MoveNext();

nItem++; } if(sSet.IsOpen())sSet.Close();}(3)編譯并運行,結果如圖8.28所示。圖8.28Ex_Student第二次運行結果voidCEx_StudentDlg::OnSelchangedTree1(NMHDR*pNMHDR,LRESULT*pResult){ NM_TREEVIEW*pNMTreeView=(NM_TREEVIEW*)pNMHDR; HTREEITEMhSelItem=pNMTreeView->itemNew.hItem;//獲取當前選擇節(jié)點

//如果當前的節(jié)點沒有子節(jié)點,那說明該節(jié)點是班級號節(jié)點

if(m_treeCtrl.GetChildItem(hSelItem)==NULL){ CString

strSelItem,str;

strSelItem=m_treeCtrl.GetItemText(hSelItem);

str.Format("studentnoLIKE'%s%%'",strSelItem.Left(6));

DispScoreAndCourseInfo(str); } *pResult=0;}6.完善兩控件的關聯(lián)代碼從上圖中可以看出,學生成績還沒有顯示出來,下面將實現(xiàn)單擊左邊的班級號,在右邊視圖中顯示該班級的所有學生成績信息。(1)CEx_StudentDlg類添加TVN_SELCHANGED消息處理:

代碼中,調(diào)用DispScoreAndCourseInfo

函數(shù)的參數(shù)是用來設置數(shù)據(jù)表(記錄集)打開的過濾條件。str是類似內(nèi)容:“studentnoLIKE210101%”,它使得所有學號前面是210101的記錄被打開。%是SQL使用的通配符,由于%也是VisaulC++格式前導符,因為在代碼中需要兩個%。(2)編譯運行并測試。9.4ADO數(shù)據(jù)庫編程ADO最主要的優(yōu)點:易于使用、速度快、內(nèi)存開銷小,它使用最少的網(wǎng)絡流量,并且在前端和數(shù)據(jù)源之間使用最少的層數(shù),它是一個輕量、高性能的接口。ADO實際上就是由一組Automation對象構成的組件(COM),因此可以像使用其它任何Automation對象一樣使用ADO。ADO中最重要的對象有三個:_ConnectionPtr、_CommandPtr和_RecordsetPtr,它們分別表示“連接”對象、“命令”對象和“記錄集”對象。9.4.1ADO編程的一般過程在MFC應用程序中使用ADO數(shù)據(jù)庫的一般過程是:①COM庫的初始化;②添加對ADO的支持;③創(chuàng)建一個數(shù)據(jù)源連接;④對數(shù)據(jù)源中的數(shù)據(jù)庫進行操作;⑤關閉數(shù)據(jù)源。1.COM庫的初始化

使用AfxOleInit()來初始化COM庫,這項工作通常在CWinApp::InitInstance()的重載函數(shù)中完成。9.4.1ADO編程的一般過程2.添加對ADO的支持

ADO編程有三種方式:使用預處理指令#import、使用MFC中的CIDispatchDriver和直接使用COM提供的API。這三種方式中,第一種最為簡便,故這里采有用這種方法。

#import"c:\programfiles\commonfiles\system\ado\msado15.dll"no_namespace

rename("EOF","adoEOF")

幾點說明:(1)您的環(huán)境中msado15.dll不一定在這個目錄下,請按實際情況修改(2)在編譯的時候肯能會出現(xiàn)如下警告,對此微軟在MSDN中作了說明,并建議我們不要理會這個警告。msado15.tlh(405):warningC4146:unaryminusoperatorappliedtounsignedtype,resultstillunsigned9.4.1_ConnectionPtr初始化:Connection

::CreateInstance("ADODB.Connection");

或Connection

::CreateInstance(__uuidof(Connection))_ConnectionPtr是Connection類的一個智能指針,返回一個記錄集或一個空指針。通常使用它來創(chuàng)建一個數(shù)據(jù)連接或執(zhí)行一條不返回任何結果的SQL語句,如一個存儲過程。使用_ConnectionPtr接口返回一個記錄集不是一個好的使用方法。通常同CDatabase一樣,使用它創(chuàng)建一個數(shù)據(jù)連接,然后使用其它對象執(zhí)行數(shù)據(jù)輸入輸出操作。打開連接:Connection::Open(

const

_variant_t

&

Source,

const

_variant_t

&

ActiveConnection,

enum

CursorTypeEnum

CursorType,

enum

LockTypeEnum

LockType,

long

Options

)關閉連接:Connection::Close(

)釋放指針:Connection::Release(

)Connection::Open(

const

_variant_t

&

Source,const

_variant_t

&

ActiveConnection,

enum

CursorTypeEnum

CursorType,enum

LockTypeEnum

LockType,

long

Options

)①Source是數(shù)據(jù)查詢字符串

②ActiveConnection是已經(jīng)建立好的連接(需要用Connection對象指針來構造一個_variant_t對象)

③CursorType光標類型,它可以是以下值之一,請看這個枚舉結構:

enum

CursorTypeEnum

{adOpenUnspecified

=

-1,///不作特別指定

adOpenForwardOnly

=

0,///前滾靜態(tài)光標。這種光標只能向前瀏覽記錄集,比如用MoveNext向前滾動,這種方式可以提高瀏覽速度。但諸如BookMark,RecordCount,AbsolutePosition,AbsolutePage

都不能使用

adOpenKeyset

=

1,///采用這種光標的記錄集看不到其它用戶的新增、刪除操作,但對于更新原有記錄的操作對你是可見的。

adOpenDynamic

=

2,///動態(tài)光標。所有數(shù)據(jù)庫的操作都會立即在各用戶記錄集上反應出來。

adOpenStatic

=

3///靜態(tài)光標。它為你的記錄集產(chǎn)生一個靜態(tài)備份,但其它用戶的新增、刪除、更新操作對你的記錄集來說是不可見的。};

④LockType鎖定類型,它可以是以下值之一,請看如下枚舉結構:

enum

LockTypeEnum

{adLockUnspecified

=

-1,///未指定

adLockReadOnly

=

1,///只讀記錄集

adLockPessimistic

=

2,悲觀鎖定方式。數(shù)據(jù)在更新時鎖定其它所有動作,這是最安全的鎖定機制

adLockOptimistic

=

3,//樂觀鎖定方式。只有在你調(diào)用Update方法時才鎖定記錄。在此之前仍然可以做數(shù)據(jù)的更新、插入、刪除等動作

adLockBatchOptimistic

=

4,樂觀分批更新。編輯時記錄不會鎖定,更改、插入及刪除是在批處理模式下完成。};

ConnectionString:連接字串,UserID:用戶名,Password:登錄密碼,Options是選項,通常用于設置同步和異步等方式。_bstr_t是一個COM類,用于字符串BSTR(用于Automation的寬字符)操作。需要說明的是,正確設置ConnectionString是連接數(shù)據(jù)源的關鍵。不同的數(shù)據(jù),其連接字串有所不同。HRESULTConnection::Open(_bstr_t

ConnectionString,_bstr_t

UserID,_bstr_t

Password,longOptions)9.4.1_ConnectionPtr9.4.1_RecordsetPtr__RecordsetPtr是一個記錄集對象。它對記錄集提供了更多的控制功能,如記錄鎖定,游標控制等。它不一定要使用一個已經(jīng)創(chuàng)建的數(shù)據(jù)連接,可以用一個連接串代替連接指針賦給__RecordsetPtr的connection成員變量,讓它自己創(chuàng)建數(shù)據(jù)連接。如果要使用多個記錄集,最好的方法是使用已經(jīng)創(chuàng)建了數(shù)據(jù)連接的全局_ConnectionPtr接口,然后使用__RecordsetPtr執(zhí)行存儲過程和SQL語句。HRESULTRecordset15::Open(const_variant_t&Source,

const_variant_t&ActiveConnection,

enum

CursorTypeEnum

CursorType,

enum

LockTypeEnum

LockType,

longOptions)讀取數(shù)據(jù):_variant_t

var=m_pRecordset->Fields->GetItem(字段名)->Value

或者:_variant_t

var=m_pRecordset->GetCollect(“Name”)

9.4.1_RecordsetPtr修改記錄:

m_pRecordset->PutCollect("Name",_variant_t(m_Name));移動指針:

m_pRecordset->MoveNext();

m_pRecordset->Move()插入記錄:

m_pRecordset->AddNew();

m_pRecordset->PutCollect("Name",_variant_t(m_Name));

m_pRecordset->PutCollect("Age",atol(m_Age));

m_pRecordset->Update();初始化:m_pRecordset->m_pRecordset.CreateInstance(__uuidof(Recordset));[例Ex_ADO]添加對ADO的支持(1)

創(chuàng)建單文檔應用程序Ex_ADO,在第6步將CEx_ADOView的基類由默認的CView選擇為CListView類。(2)

在CEx_ADOView::PreCreateWindow函數(shù)添加下列代碼,用來設置列表視圖內(nèi)嵌列表控件的風格:BOOLCEx_ADOView::PreCreateWindow(CREATESTRUCT&cs){

cs.style|=LVS_REPORT;//報表風格

returnCListView::PreCreateWindow(cs);}(3)在stdafx.h文件中添加對ADO支持的代碼:#endif//_AFX_NO_AFXCMN_SUPPORT#include<afxcmn.h>//MFCsupportforWindowsCommonControls#import"C:\ProgramFiles\CommonFiles\System\ADO\msado15.dll"\no_namespacerename("EOF","adoEOF")#include<icrsint.h>//{{AFX_INSERT_LOCATION}}

預編譯命令#import是編譯器將此命令中所指定的動態(tài)鏈接庫文件引入到程序中,并從動態(tài)鏈接庫文件中抽取出其中的對象和類的信息。

icrsint.h文件包含了VisualC++擴展的一些預處理指令、宏等的定義,用于與數(shù)據(jù)庫數(shù)據(jù)綁定。(4)CEx_ADOApp::InitInstance添加代碼,用來對ADO的

COM環(huán)境進行初始化BOOLCEx_ADOApp::InitInstance(){::CoInitialize(NULL);

AfxEnableControlContainer(); …}(5)在Ex_ADOView.h文件中為CEx_ADOView定義三個ADO對象指針變量:public:_ConnectionPtr

m_pConnection;_RecordsetPtr

m_pRecordset;_CommandPtr

m_pCommand;_ConnectionPtr、_RecordsetPtr和_CommandPtr分別是ADO對象Connection、Recordset和Command的智能指針類型。2.連接數(shù)據(jù)源

ADO使用Connection對象來建立與數(shù)據(jù)庫服務器的連接,它相當于MFC的CDatabase類。和CDatabase類一樣,調(diào)用Connection對象的Open即可建立與服務器的連接。HRESULTConnection::Open(_bstr_t

ConnectionString,_bstr_t

UserID,_bstr_t

Password,longOptions)voidCEx_ADOView::OnDestroy(){ CListView::OnDestroy(); if(m_pConnection)m_pConnection->Close();//關閉連接 }3.關閉連接

CEx_ADOView映射WM_DESTROY消息,并添加下列代碼:4.獲取數(shù)據(jù)源信息Connection對象除了建立與數(shù)據(jù)庫服務器的連接外,還可以通過OpenSchema來獲取數(shù)據(jù)源的自有信息。下面的代碼用來獲取student.mdb的數(shù)據(jù)表名和字段名,并將內(nèi)容顯示在列表視圖中:voidCEx_ADOView::OnInitialUpdate(){

CListView::OnInitialUpdate();//初始化Connection指針

m_pConnection.CreateInstance(__uuidof(Connection));//初始化Recordset指針

m_pRecordset.CreateInstance(__uuidof(Recordset));//初始化Recordset指針

m_pCommand.CreateInstance(__uuidof(Command));

//連接數(shù)據(jù)源為"DatabaseExampleForVC++"

m_pConnection->ConnectionString="DSN=DatabaseExampleForVC++";

//允許連接超時時間,單位為秒

m_pConnection->ConnectionTimeout=30;HRESULThr=m_pConnection->Open("","","",0);//獲取數(shù)據(jù)表名和字段名

if(hr!=S_OK)

MessageBox(“無法連接指定的數(shù)據(jù)庫!”);_RecordsetPtr

pRstSchema=NULL; //定義一個記錄集指針

//獲取表信息

pRstSchema=m_pConnection->OpenSchema(adSchemaColumns);//將表信息顯示在列表視圖控件中

CListCtrl&m_ListCtrl=GetListCtrl();

CStringstrHeader[3]={"序號","TABLE_NAME","COLUMN_NAME"};for(inti=0;i<3;i++)

m_ListCtrl.InsertColumn(i,strHeader[i],LVCFMT_LEFT,120);

int

nItem=0;

CString

str;_bstr_t

value;

while(!(pRstSchema->adoEOF)){str.Format("%d",nItem+1);

m_ListCtrl.InsertItem(nItem,str); for(inti=1;i<3;i++){value=pRstSchema->Fields->GetItem((_bstr_t)(LPCSTR)strHeader[i])->Value;

m_ListCtrl.SetIt

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論