哈爾濱工程大學計算中心 李健萍 李春艷 張積東
摘要
---- 本文較為詳細的介紹了一個使用ODBC對數據庫進行操作的CdataBaseOperate類的建立,并給出了幾個主要函數的具體實現,以及該類在實際的應用程序中的使用。
---- 眾所周知VC++的MFC類庫為編程者編制好了對數據庫操作的類,編程者可以使用向導建立一個與數據庫聯結并對數據庫進行操作的應用程序,不需要編制任何代碼,這無疑為編程人員提供了一個捷徑。但是,使用向導時只有選用基于單文檔或多文檔的項目才能選擇數據源,與指定的的數據庫相連,對用向導生成的基于對話框的應用程序不提供數據庫的支持。即使是基于單文檔或多文檔的應用程序,當需要一些特殊的操作,例如,打開一個表,要求返回滿足一定條件的記錄集時,MFC并沒有提供完全符合要求的現成函數。如果,能利用MFC所提供的數據庫操作,再加上自己設計的函數,也就是說,設計一個對數據庫操作的類,在程序中手工加入這個類,那么就可以在基于對話框的應用程序中實現對數據庫的操作,而且,也可以針對自己應用程序的具體需要來設計類的函數,為特定功能的實現提供了很大的方便。
---- 在一個涉及數據庫操作的應用程序中,常用到的MFC類有CdaoDatabase類、CdaoTableDef類、CdaoRecordset類和 CdaoQueryDef類,當對數據庫進行操作時,需要先打開數據庫,然后打開數據庫中的表,再得到查詢集和記錄集。在自己定義的類中綜合這四個類的操作,設計一個打開表得到查詢集和記錄集的函數,以后,在應用程序中使用該類時只需包含該類的頭文件,所設計的函數就可以直接調用了。
---- 建立數據庫類的過程可分為如下四步:
---- 一、定義一個無基類的CdataBaseOperate類
---- 1、在Workspace窗口選擇ClassView選項卡,在樹型類結構圖的根部單擊鼠標右鍵,選擇New Class…,系統將彈出建立新類的對話框;
---- 2、在Class type中選擇Generic Class;
---- 3、在Name中填寫要建的新類的名稱,要以大寫字母C開頭,系統會自動建立新類的頭文件和實現文件,文件的名稱為類名去掉第一個大寫字母C,如果想改變文件的名稱,可以單擊change按鈕.
---- 4、在填寫好各項后,按OK按鈕確定,一個無基類的新類建立成功,但,他還是一個空類,下一步,就要給類添加內容.
---- 二、在自定義的類中加入有關的定義
---- 1、在本應用程序中,使用ODBC與SQL SERVER的數據庫相連,因而,在類的實現文件構造函數前加入如下的定義: #define SQL_DATABASE _T("ODBC;DSN=sql-database;UID=sa;PWD=pass;") DSN=sql-database表示建立的ODBC聯接的名稱是sql-database,如果選用其他數據庫,只需在此改變與所需數據庫建立的聯接,或是重新配置sql-database 使之聯接新的數據庫。UID=sa;PWD=pass表示登錄數據庫的用戶名是sa,密碼是pass,如果密碼是空則表示為PWD=""。
---- 2、在該類中綜合使用到了MFC類庫提供的有關數據庫的幾個類CdaoDatabase類、CdaoTableDef類、CdaoRecordset類和CdaoQueryDef類,而這四個類的定義和實現都包括在頭文件afxdao.h中,因此,在新定義的類的頭文件中一定要加上語句:
#include < afxdao.h >;
---- 3、對要用到的四個類各聲明一個對象如下: CDaoDatabase* loc_pDataBase; CDaoTableDef* loc_pTable; CDaoRecordset loc_pRecordset; CDaoQueryDef* loc_pQueryDef;
---- 其中CdaoDatabase類、CdaoTableDef類和CdaoQueryDef類定義了對象指針,在使用時要先new,最后要delete。以CdaoDatabase類為例,在CdataBaseOperate類的構造函數中初始化對象指針 loc_pDataBase=new CDaoDatabase;在析構函數中要釋放該指針delete loc_pDataBase; ---- 三、在自定義的類中加入所需的函數和變量
---- 手工加入函數包括兩項工作,首先在頭文件中加入函數的聲明,然后,在實現文件中加入函數的具體實現,聲明與實現一定要統一;
---- 使用向導加入函數和變量:
---- 1、在Workspace窗口選擇ClassView選項卡;
---- 2、在樹型類結構圖的要添加函數和變量的類上單擊鼠標右鍵,如果加入成員函數則單擊Add Member Function,加入虛函數單擊Add Virtual Function,加入成員變量單擊 Add Member Variable;
---- 3、出現對話框后,填寫成員函數或變量的名稱、類型,系統會自動添加函數的聲明與實現;
---- 4、添加函數的具體操作,可以通過編輯代碼進一步填寫;
---- 這些操作將會在Workspace窗口的ClassView選項中立即體現出來,并且,單擊ClassView中的相應函數就可進入該函數的實現部分,進行進一步編寫代碼,如果做不到這一點,說明添加成員函數的操作有誤。
---- 下面以本應用程序為例,給出具體的表結構和幾個主要函數的實現,讀者可以根據自己的實際情況設計函數。
---- 本應用程序中的一個典型表的結構是:
序號 正題內容 難度系數 分值 答案 備注 整型 字符型 長整型 雙精度 字符型 字符型
---- 打開數據庫的函數實現如下: if (!loc_pDataBase->IsOpen()) loc_pDataBase->Open( NULL, FALSE, FALSE, SQL_DATABASE);
---- 該函數中用到了CdaoDatabase類的兩個函數IsOpen()和Open(NULL, FALSE, FALSE, SQL_DATABASE),因為已經聲明了該類的指針對象loc_pDataBase,所以可以直接調用CdaoDatabase類的函數。其中,Open()函數中的最后一個參數SQL_DATABASE在前面已經介紹過,通過他打開相關的數據庫。 ---- 由于程序中打開表后,不僅要返回所有的記錄集,還用到返回滿足一定條件的記錄集,因此打開表的函數除了帶入表名外還有一個參數難度系數,lNDXS=0時,選擇表中全部數據, lNDXS=1~n時,表示選擇難度系數=1~n的記錄。
bool CDataBaseOperate::OpenTable (CString strTableName,long lNDXS) { CString strFieldNumber; loc_pTable=new CdaoTableDef (loc_pDataBase); if (!loc_pTable->IsOpen()) loc_pTable->Open(strTableName); //打開指定的表名 strFieldNumber.Format("%d",loc_pTable- > GetFieldCount()); //得到字段數 CString Sqlstr,Sqlstr1,Sqlstr2; loc_pQueryDef=new CDaoQueryDef(loc_pDataBase); //得到查詢集和記錄集 if (lNDXS==0) { Sqlstr=_T("SELECT * FROM "+strTableName); } else { Sqlstr1="SELECT * FROM "+strTableName ; Sqlstr2.Format("WHERE 難度系數= %d",lNDXS); Sqlstr=_T(Sqlstr1+Sqlstr2); } loc_pQueryDef->Create(NULL,Sqlstr); loc_pRecordset.Open(loc_pQueryDef); m_nRecordNumber=0; while(!loc_pRecordset.IsEOF()) { m_nRecordNumber++; loc_pRecordset.MoveNext( ); } return TRUE; }
---- 為了維護數據庫的安全,表用過后應該關閉,關閉表的同時,要釋放在打開表的操作時初始化的對象指針,例如:delete loc_pQueryDef。同樣要注意,在構造函數中初始化的對象指針,在析構函數中一定要釋放。對象指針的初始化和釋放是成對出現的。 loc_pDataBase=new CDaoDatabase; //在構造函數中初始化對象指針。 delete loc_pDataBase; //在析構函數中釋放該對象指針。
---- 四、CdataBaseOperate類的應用 ---- 1、使用VC++的向導生成一個應用程序,可以根據需要選擇基于對話框或是基于單、多文檔,選擇單文檔或多文檔時不要選擇數據庫支持。
---- 2、在應用程序的主頭文件中加入#include "DataBaseOperate.h",并且還要聲明一個CdataBaseOperate類的對象,public: CDataBaseOperate m_CDataBaseOperate;
---- 3、有了指向CdataBaseOperate類的對象后,剛剛在CdataBaseOperate類中編制的函數都可以通過 "m_CdataBaseOperate .函數名"來調用。
小結:
---- 本文是VC++6.0下的CdataBaseOperate類建立與應用的一個初步探討,CdataBaseOperate類所實現的功能是很強大的。除了介紹的CdataBaseOperate類的幾個基本而又常用的函數之外,CdataBaseOperate還有很多用于其他方面的功能函數,在此不一一介紹。CdataBaseOperate類的函數,實現了數據庫內容的顯示、修改、添加、刪除等功能,基本上滿足了數據庫操作人員的需要。除了這些,編程人員還可以根據程序的需要定義自己的特有的函數。
---- 本文所提供的程序均在VC++ 6.0中編譯通過。
---- 附錄:CdataBaseOperate類的頭文件和原文件
附錄:CdataBaseOperate類的頭文件和原文件: // DataBaseOperate.h: interface for the CDataBaseOperate class. ////////////////////////////////////////////////////////////////////// #if !defined(AFX_DATABASEOPERATE_H__90468D61_8978_11D3_BA46_000021ECD4C4__INCLUDED_) #define AFX_DATABASEOPERATE_H__90468D61_8978_11D3_BA46_000021ECD4C4__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include <afxdao.h> class CDataBaseOperate {public: CDataBaseOperate(); virtual ~CDataBaseOperate(); CDaoDatabase* loc_pDataBase; CDaoTableDef* loc_pTable; CDaoRecordset loc_pRecordset; CDaoQueryDef* loc_pQueryDef; //以下的五個變量代表從一個數據庫中得到一條記錄的值 CString m_strZTNRvalue,m_strDAvalue,m_strBZvalue; long m_nNDXSvalue; double m_nFZvalue; CString m_strTableName; //得到要打開的表名 int m_nNumberPosition; //記住一開始帶入的記錄位置 int m_nRecordNumber; //得到打開表的記錄數 bool OpenDataBase(); bool OpenTable(CString strTableName); //打開表,帶入表名 bool CloseTable(); //在打開其他的表時,先關閉已打開的表 //得到一條記錄的值,值放在以上五個變量中,帶入的參數為要得到的記錄序號 bool GetRecord(int nRecordPosition); //以下五個函數將帶出一條記錄的五個值 CString GetZTNRvalue(); //得到正題內容字段值 long GetNDXSvalue(); //得到難度系數字段值 double GetFZvalue(); //得到分值字段值 CString GetDAvalue(); //得到答案字段值 CString GetBZvalue(); //得到備注字段值 bool MoveFirst(); bool MoveLast(); bool MovePrev(); bool MoveNext(); }; #endif // !defined(AFX_DATABASEOPERATE_H__90468D61_8978_11D3_BA46_000021ECD4C4__INCLUDED_) // DataBaseOperate.cpp: implementation of the CDataBaseOperate class. ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "NewCai.h" #include "DataBaseOperate.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif #define SQL_DATABASE _T("ODBC;DSN=sql-database;UID=sa;PWD="";") ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CDataBaseOperate::CDataBaseOperate() { loc_pDataBase=new CDaoDatabase; CString m_strFieldvalue; }
CDataBaseOperate::~CDataBaseOperate() { delete loc_pDataBase; }
bool CDataBaseOperate::OpenDataBase() { if (!loc_pDataBase->IsOpen()) loc_pDataBase->Open( NULL, FALSE, FALSE, SQL_DATABASE ); return TRUE; }
bool CDataBaseOperate::CloseTable() { if (loc_pRecordset.IsOpen()) { loc_pRecordset.Close(); delete loc_pQueryDef; delete loc_pTable; } return TRUE; } bool CDataBaseOperate::MoveFirst() { loc_pRecordset.MoveFirst(); m_nNumberPosition=1; GetRecord(m_nNumberPosition); return TRUE; }
bool CDataBaseOperate::MoveLast() { loc_pRecordset.MoveLast(); m_nNumberPosition=m_nRecordNumber; GetRecord(m_nNumberPosition); return TRUE; }
bool CDataBaseOperate::MovePrev() { loc_pRecordset.MovePrev(); m_nNumberPosition--; if(loc_pRecordset.IsBOF()) { loc_pRecordset.MoveFirst(); m_nNumberPosition=1; } GetRecord(m_nNumberPosition); return TRUE; }
bool CDataBaseOperate::MoveNext() { m_nNumberPosition++; loc_pRecordset.MoveNext(); if(loc_pRecordset.IsEOF()) { loc_pRecordset.MoveLast(); m_nNumberPosition=m_nRecordNumber; } GetRecord(m_nNumberPosition); return TRUE; }
bool CDataBaseOperate::OpenTable(CString strTableName) { CString strFieldNumber; loc_pTable=new CDaoTableDef(loc_pDataBase); if (!loc_pTable->IsOpen()) loc_pTable->Open(strTableName); //打開指定的表名 strFieldNumber.Format("%d",loc_pTable->GetFieldCount()); //得到字段數 CString Sqlstr; //得到查詢集和記錄集 loc_pQueryDef=new CDaoQueryDef(loc_pDataBase); Sqlstr=_T("SELECT * FROM "+strTableName); loc_pQueryDef->Create(NULL,Sqlstr); loc_pRecordset.Open(loc_pQueryDef); m_nRecordNumber=0; while(!loc_pRecordset.IsEOF()) { m_nRecordNumber++; loc_pRecordset.MoveNext( ); } return TRUE; }
bool CDataBaseOperate::GetRecord(int nRecordPosition) { //得到字段名 CDaoFieldInfo fieldinfo; CString strZTNRName,strNDXSName,strFZName,strDAName,strBZName; m_nNumberPosition=nRecordPosition; loc_pTable->GetFieldInfo(1,fieldinfo,AFX_DAO_PRIMARY_INFO); strZTNRName=fieldinfo.m_strName; loc_pTable->GetFieldInfo(2,fieldinfo,AFX_DAO_PRIMARY_INFO); strNDXSName=fieldinfo.m_strName; loc_pTable->GetFieldInfo(3,fieldinfo,AFX_DAO_PRIMARY_INFO); strFZName=fieldinfo.m_strName; loc_pTable->GetFieldInfo(4,fieldinfo,AFX_DAO_PRIMARY_INFO); strDAName=fieldinfo.m_strName; loc_pTable->GetFieldInfo(5,fieldinfo,AFX_DAO_PRIMARY_INFO); strBZName=fieldinfo.m_strName; int iNumber=1; COleVariant OleField; loc_pRecordset.MoveFirst(); //得到指定記錄的字段值,存入五個變量中 while(!loc_pRecordset.IsEOF()) { if (iNumber==nRecordPosition) { loc_pRecordset.GetFieldvalue(strZTNRName,OleField); m_strZTNRvalue=(CString)V_BSTRT(&OleField); m_strZTNRvalue.TrimRight(); loc_pRecordset.GetFieldvalue(strNDXSName,OleField); m_nNDXSvalue=(long)V_I4(&OleField); loc_pRecordset.GetFieldvalue(strFZName,OleField); m_nFZvalue=(double)V_R8(&OleField); loc_pRecordset.GetFieldvalue(strDAName,OleField); m_strDAvalue=(CString)V_BSTRT(&OleField); m_strDAvalue.TrimRight(); loc_pRecordset.GetFieldvalue(strBZName,OleField); m_strBZvalue=""; m_strBZvalue=(CString)V_BSTRT(&OleField); m_strBZvalue.TrimRight(); loc_pRecordset.MoveLast(); loc_pRecordset.MoveNext(); } else { loc_pRecordset.MoveNext( ); iNumber++; } } loc_pRecordset.MoveFirst(); int jj=1; while (jj<nRecordPosition) { loc_pRecordset.MoveNext(); jj++; } return TRUE; } CString CDataBaseOperate::GetZTNRvalue() { return m_strZTNRvalue;} long CDataBaseOperate::GetNDXSvalue() { return m_nNDXSvalue;} double CDataBaseOperate::GetFZvalue() { return m_nFZvalue;} CString CDataBaseOperate::GetDAvalue() { return m_strDAvalue;} CString CDataBaseOperate::GetBZvalue() { return m_strBZvalue;}
|