程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#基礎知識 >> 用VC++6.0設計多表聯接地數據庫運用程序

用VC++6.0設計多表聯接地數據庫運用程序

編輯:C#基礎知識

  本文介紹了用Visual C++6.0開發數據庫應用程序時,使用MFC ODBC類的編程方法,詳細說明了在MFC ODBC的派生類中設置SQL語句參數的方法,實現了二個表的關聯。

1.引言
開發Windows應用程序時,在很多情況下可能要和數據庫連接。數據庫類型多種多樣,功能結構也各不相同。從比較簡單的DBASE、FoxPro等到復雜的SYBASE、Qracle等大型數據庫系統。VC++6.0都提供了一些接口。程序員可利用這些接口方便地開發數據庫應用程序。MFC ODBC類就是其中的一個,在快速生成簡單一致的接口應用程序方面這些類非常有用。用戶不必了解ODBC API和SQL的具體細節,利用ODBC類即可完成對數據庫的大部分操作。然而,VC++ Appwizard 生成的數據庫應用程序,只是基於單個數據表的數據庫應用程序。而實際應用中,往往要求數據庫應用程序能關聯二個或多個數據表。VC++的好多書籍對此只是簡單的介紹。本文透徹地解決這一問題。
2.ODBC與MFC
2.1 ODBC
ODBC(開放數據庫互連)應用程序可通過ODBCAPI訪問不同數據源中的數據,每個不同的數據源類型由一個ODBC驅動程序支持,這個驅動程序完成了ODBC API程序的核心,並與具體的數據庫通信。ODBC環境提供了驅動程序管理器(Driver Manager),管理那些與不同數據源連接的驅動程序在ODBC32.DLL中執行。應用程序只需要與驅動程序管理器連接,驅動程序管理器就會根據應用程序提供的數據源名,選擇正確的驅動程序來訪問數據源。
要使用ODBC來開發數據庫應用程序,必須使用在控制面板處的ODBC數據源管理器,來建立、配制數據源。應本例應用程序需要,按以下步驟建立所需的數據源。
1. 雙擊控制面板處的32位的ODBC程序,選擇對話框中的User DSN(用戶數據源名)選項卡。
2. 單擊Add按鈕,然後選擇一個數據源:Microsoft Visual FoxPro Driver。單擊“完成”,進入下一步設置。
3. 在Data Source Name域內輸入數據源名:DB-FSB。然後選擇Visual FoxPro數據庫的位置。
4. 單擊OK按鈕,返回到控制面板。
2.2 MFC ODBC
MFC的數據庫擴展部分封裝了使用ODBC數據資源的細節,提供了VC++與ODBC間一種簡單的調用接口。MFC的ODBC類主要包括:用來與一個數據源相連的CDatabase類;用來處理從數據庫返回的一組記錄集的CRecordset類;簡化從Crecordset對象中得到數據的顯示的CRecordView類。
雖然Cdatabase類允許你對一個數據庫執行SQL語句,但是CRecordset類提供了應用程序與數據交互的實質。本例應用程序使用CRecordset類來操作數據源.
CRecordset類的主要目的是讓應用程序訪問從數據庫中返回的結果集。在應用程序中要使用CRecordset類,可根據數據源並使用VC++中的ClassWizard來創建Crecordset派生類。通常,一個CRecordset派生類對應用戶數據源中的一個表。每生成一個Crecordset派生類,就要選擇一個數據源和一個數據源中的一個表。若生成一個Crecordset派生類時,選擇了一個數據源中的多個表,那麼Crecordset派生類中的結果集是多個表的卡氏積(迪卡爾積)連接,顯然,在實際應用中沒什麼意義。應用程序通過派生出的Crecordset類可對記錄集中的記錄進行滾動、修改、增加和刪除等操作。
CRecordView類具有幾個增強功能,允許使用對話框方式(DoDataExchange()函數)直接從記錄集顯示數據,使得從記錄集中顯示數據更為容易。並提供了記錄移動等操作。
3. 多表聯接的數據庫應用程序
3. 1本例程序功能:
通過FSB表的BZM字段及DBK1表的HH字段,將Visual FoxPro 的 FSB表與DBK1表(結構如下)關聯起來。程序運行出現界面如圖1。用鼠標點擊工具條的?、?、(、(則FSB表記錄移動而DBK1表的記錄沒移動。用鼠標點擊“關聯”按鈕,則DBK1表的記錄和FSB表記錄同步移動(BZM編輯框內容與HH編輯框內容相同)。如果,要求按照具體的關鍵字值來查詢二個表中的相關記錄,那麼,在“定位” 編輯框中輸入具體的關鍵字值,然後,用鼠標點擊“關聯”按鈕,就會見到二個表在新的記錄集實現關聯。

表1: FSB表結構
字段名
類型
備注
BZM
C
索引關鍵字
DGDL1
N

DGZD1
N

其它字段



表2: DBK1表
字段名
類型
備注
HH
C
索引關鍵字
BL
N

ZZCM
C

其它字段



基於MFC ODBC類開發的數據庫應用程序,是通過MFC ODBC類使用SQL語句方式操縱數據表的。數據庫中表FSB與表DBK1關聯查詢的SQL語句是:
SELECT * FROM FSB,DBK1 WHERE FSB.BZM=DBK1.HH
由於創建一個CRecordset派生類時,一般只選擇一個數據源中的一個表,因此基於MFC ODBC類開發的數據庫應用程序要實現二個表關聯,就要使用CRecordset類的參數m _strFilter。它相當於SQL語句中的WHERE子句。參數m _strSort相當於SQL語句中的GROUP BY子句。要注意m_strFilter字符串中不要包含“WHERE”關鍵字。本例在表FSB與表DBK1對應的CRecordset派生類中分別使用了mbzm和mhh二個m _strFilter參數。用鼠標點擊“關聯”按鈕時,程序首先根據“定位” 編輯框中的內容作為mbzm的值,在表FSB檢索結果集。表DBK1對應的CRecordset派生類根據表FSB對應的CRecordset派生類的當前記錄m_bzm值,作為mhh的值實行檢索,從而得到與表FSB關鍵字段BZM對應的表DBK1的記錄。實現了表FSB與表DBK1的關聯。由此可見,二表關聯的關鍵是m _strFilter參數的設置。

圖 1
3.2 數據庫應用程序創建
3.2. 1 創建單表單文檔的數據庫應用程序
根據前面建立的數據源DB-FSB,使用VC++ Appwizard 生成一個單表單、單文檔的數據庫應用程序。選擇數據源DB-FSB的數據表時應選擇FSB.DBF。應用程序名為ZF0001(具體步驟可參考有關VC++資料)。ZF0001應用程序中創建了CZf0001Doc、CZf0001Set、CZf0001View等派生類。
3.2.2 設置m _strFilter參數
在上一步生成的CZf0001Set類中,按以下方式,在① ② ③程序中設置m _strFilter參數(黑體部分的語句都是為CZf0001Set的參數mbzm而手動增加的)。為節省篇幅,省略程序清單的部分內容。
①. 在Crecordset派生類的定義中,描述了被連接的數據源表的字段,並在VC++ Appwizard 生成的程序注釋“// Field/Param Data ”中提示在此可定義參數。
CRecordset派生類:CZf0001Set的定義
class CZf0001Set : public Crecordset //Crecordset派生類CZf0001Set
{
public:
CZf0001Set(CDatabase* pDatabase = NULL);
DECLARE_DYNAMIC(CZf0001Set)
// Field/Param Data
//{{AFX_FIELD(CZf0001Set, CRecordset) //被綁定的字段
CString m_bzm;
CString m_dgqd1;
、、、、、、 //為節省篇幅,省略部分字段
CString m_bz;
//}}AFX_FIELD
CString mbzm; // 參數mbzm
// Overrides
// ClassWizard generated virtual function overrides
、、、、、、、
virtual void Dump(CDumpContext& dc) const;
#endif
};
②.Crecordset派生類:CZf0001Set的構造函數
其中,對被綁定字段的相應內存變量進行了初始化。
CZf0001Set::CZf0001Set(CDatabase* pdb) : CRecordset(pdb)
{
//{{AFX_FIELD_INIT(CZf0001Set)
m_bzm = _T("");
m_dgqd1 = _T("");
、、、、、、
m_bz = _T("");
m_nFields = 16; //數據源表的記錄字段個數
//}}AFX_FIELD_INIT
m_nDefaultType = snapshot;
m_nParams=1; // CZf0001Set的參數個數
mbzm=""; //參數初始化
}
③.記錄字段交換(RFX)
通過使用RFX,MFC框架可以在數據庫和CRecordset類變量之間交換。交換是通過執行DoFieldExchange()函數而建立的。
void CZf0001Set::DoFieldExchange(CFieldExchange* pFX)
{
//{{AFX_FIELD_MAP(CZf0001Set)
pFX->SetFieldType(CFieldExchange::outputColumn);
RFX_Text(pFX, _T("[bzm]"), m_bzm);
RFX_Text(pFX, _T("[dgqd1]"), m_dgqd1);
、、、、、、;
RFX_Text(pFX, _T("[dgdl2]"), m_dgdl2);
RFX_Text(pFX, _T("[bz]"), m_bz);
//}}AFX_FIELD_MAP
pFX->SetFieldType(CFieldExchange::param);
//把字段類型設為CFieldExchange::param
RFX_Text(pFX,"mbzm",mbzm); //為參數設置RFX 宏,如果有多個參數,必須按SQL的語句中的位置標志符的順序設置,RFX 宏中的參數的名字如"mbzm",並非用來與參數匹配,可以自己定義。
}
3.2.3 增加第二個表,並設置第二個表的參數
在3。2。1創建的數據庫應用程序基礎上,進入ClassWizard,點擊Add Class...按鈕並在彈出的菜單中選擇New...,然後在Create New Class對話框中的Name欄中輸入CZf1001,在Base class欄中選擇CRecordset,按Create按鈕。
在彈出的Database Options對話框中,在ODBC組合框裡選擇DB-FSB數據源。然後按OK按鈕。在彈出的Select Database Tables對話框中選擇DBK1表。按OK確認。並在所有存在 #include "CZf0001Set.h" 的文件中,都加入#include "CZf1001.h" 。這樣就創建了與DBK1表對應的Crecordset派生類。
在第一步創建的CZf0001Doc類中,增加一個CZf1001 對象的指針變量m_zf1002(即:CZf1001* m_zf1002)。
按3.2.2介紹的CZf0001Set類m _strFilter參數的設置方法,在CZf1001類中,設置參數mhh。
3. 3 參數mhh及參數mbzm在CrecordView的派生類CZf0001View中的使用
3.3.1 參數在CZf0001View::OnInitialUpdate()函數使用
在CZf0001View::OnInitialUpdate()函數的開頭部分,調用CZf0001View:: GetDocument()從文檔類CZf0001Doc類中,返回二個CrecordSet類(CZf0001Set、CZf1001)的指針。根據返回的指針,設置m _strFilter (相當於SQL語句的WHERE子句),並確定二個參數的初始值。這裡要說明一點:
m_pSet->m_strFilter="BZM like ?";
m_pSet2->m_strFilter="hh like ?";
語句中的“?”,在調用Open或Requery時,“?"將分別自動地被CZf0001Set::mbzm和 CZf1001::mhh的值取代。例如,指定mbzm為“31001",則m_pSet->m_strFilter將變成"BZM =31001"。這樣用戶只要指定了mbzm,就可以得到所需要的記錄集。CZf0001View::OnInitialUpdate()的程序清單如下(黑體部分的語句是手工增加的):
void CZf0001View::OnInitialUpdate()
{ m_pSet = &GetDocument()->m_zf0001Set;
m_pSet2=&GetDocument()->m_zf1002;
if(!m_pSet2->Open())
return;
m_pSet->m_strFilter="BZM like ?";
m_pSet->mbzm= "%"; //初始選擇所有記錄
m_pSet->m_strSort="";
m_pSet2->m_strFilter="hh like ?";
m_pSet2->mhh=m_pSet->m_bzm; //將表FSB對應的CRecordset派生類的m_bzm的值,作為參數mhh的值 
m_pSet2->m_strSort="";  //檢索的結果不進行排序
m_pSet->m_pDatabase= m_pSet2->m_pDatabase; //共享CDatabase

CRecordView::OnInitialUpdate();
GetParentFrame()->RecalcLayout();
ResizeParentToFit();
}
3.3.2 在對話框中加入編輯框
在資源視圖Dialog的IDD_ZF0001_FORM表單中,加入用戶需要的編輯框。用ClassWizard在第一個表FSB中選擇有關字段與它們相連。但是.使用ClassWizard無法找到第二個表DBK1字段變量,因此,對於計劃與第二個表DBK1字段相連的編輯框,必須用手工修改CRecordView類的DoDataExchange()(對話框數據交換函數)。 在DoDataExchange()函數 “//}}AFX_DATA_MAP” 後面加入有關內容。見下面程序的黑體部分。如果黑體部分語句加在“//}}AFX_DATA_MAP”的前面,那麼,要再次修改IDD_ZF0001_FORM表單時,就無法使用ClassWizard.
void CZf0001View::DoDataExchange(CDataExchange* pDX)
{
CRecordView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CZf0001View)
DDX_Control(pDX, IDC_COMBO1, m_comb);
DDX_Control(pDX, IDC_EDIT4, m_SS);
DDX_FieldText(pDX, IDC_EDIT2, m_pSet->m_bl1, m_pSet);
DDX_FieldText(pDX, IDC_EDIT3, m_pSet->m_dgdl1, m_pSet);
DDX_FieldCBString(pDX, IDC_COMBO1, m_pSet->m_bzm, m_pSet);
DDX_FieldText(pDX, IDC_EDIT5, m_pSet->m_dgqd1, m_pSet);
//}}AFX_DATA_MAP
DDX_FieldText(pDX, IDC_EDIT1, m_pSet2->m_bl, m_pSet2);
DDX_FieldText(pDX, IDC_EDIT6, m_pSet2->m_hh, m_pSet2);
DDX_FieldText(pDX, IDC_EDIT7, m_pSet2->m_zzcm, m_pSet2);
}
3.3.3 在對話框中加入一個按鈕
為演示二個表關聯的效果,在對話框中加入一個“關聯”按鈕和一個輸入參數用的"定位"編輯框。並給此按鈕增加單擊事件代碼如下:

void CZf0001View::OnButton1()
{
// TODO: Add your control notification handler code here
char ll[11];
int nn=0;
m_SS.GetLine(0,ll); //讀“定位”編輯框中的內容
nn=m_SS.LineLength(0); //讀“定位”編輯框中的字符內容的長度
if(nn) //“定位”編輯框中有輸入內容,則按內容檢索形成新的記錄集
{ m_pSet->mbzm=(CString)ll;
m_pSet->mbzm=m_pSet->mbzm.Left(nn)+"%"; //“%”由SQL語法規定代表任意長度(長度可以為0)的字符串
m_pSet->Requery(); //在表FSB中重新檢索
if(m_pSet->IsEOF())
{ MessageBox("檢索結果為空!");
UpdateData(FALSE);
m_pSet->mbzm="%";
m_pSet->Requery();
}
m_pSet2->Requery(); //以表1當前記錄BZM值,在表2:DBK1中檢索
UpdateData(FALSE); //刷新表單內容
m_SS.SetSel(0,-1);
m_SS.ReplaceSel(""); //清除“定位”編輯框中的內容,使下一次單擊“關聯”按鈕時,不會重復檢索(即使nn=0)
}
else //“定位”編輯框為空,則按表1現有的結果集與表2:DBK1關聯
{
m_pSet2->mhh=m_pSet->m_bzm; //將表1當前記錄BZM值,作為表DBK1的查找參數
m_pSet2->Requery();
UpdateData(FALSE);
m_pSet->MoveNext();
}
}
4. 小結
通過本例可知,雖然VC++提供了Appwizard和Classwizard, 為編程者節省了大量的工作,但是想編出優秀的VC++應用程序,僅憑這些是遠遠不夠的;必須熟悉MFC類庫、ActiveX控件等知識。本文作為一個例子介紹了二個表的聯接方法。在實際的應用中,讀者可以舉一翻三,編制更加完善的數據庫應用程序。

參考文獻
1. 康博創作室等編著. Visual C++6.0 高級開發教程. 人民郵電出版社
2. 齊舒創作室 編著. Visual C++6.0編程技巧與實例分析. 中國水利水 電出版社
3. 官章全 劉加明編著. Visual C++6.0 類庫大全. 電子工業出版社

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved