3.1 概述
VisualC++的MFC類庫定義了幾個數據庫類。在利用ODBC編程時,經常要使用到CDatabase(數據庫類),CRecordSet(記錄集類)和CRecordView(可視記錄集類)。 其中:
CDatabase類對象提供了對數據源的連接,通過它你可以對數據源進行操作。
CRecordView類對象能以控制的形式 顯示數據庫記錄。這個視圖是直接連到一個CRecordSet對象的表視圖。
CRecordSet類對象提供了從數據源 中提取出的記錄集。CRecordSet對象通常用於兩種形式: 動態行集(dynasets)和快照集(snapshots)。動態行集能保 持與其他用戶所做的更改保持同步。快照集則是數據的一個靜態視圖。每一種形式在記錄集被打開時都提供一組記錄,所不同的是,當你在一個動態行集裡滾 動到一條記錄時,由其他用戶或是你應用程序中的其他記錄集對該記錄所做的更改會相應地顯示出來。
Visual C++提供了幾種記錄集,可以用來定制應用程序的工作方式。查看這些不同選項的最快方式要兼顧速度和特征。你會發現,在很多情況下,如果想添加特征,就必須付出程序執行速度降低的代價。下面告訴你一些可以自由支配的記錄集選項。更重要的是,要告訴你從這個選項可以獲得更快的速度還是更多的特征。
1、Snapshot(快照) 這個選項要Visual C++在一次快照中下載整個查詢。換言之,及時快速地給數據庫內容拍照,並把它作為未來工作的基礎。這種方法有三個缺點。第一,你看不到別人在網絡上做的更新,這可能意味著你的決定是建立在老信息的基礎上。第二,一次就下載所有這些記錄,這意味著在下載期間給網絡增加了沉重的負擔。第三,記錄下載時用戶會結束等待,這意味著網絡的呼叫性能變得更低。然而這種方法也有兩個優點。第一,記錄一旦被下載,該工作站所需的網絡活動幾乎就沒有了棗這為其它請求釋放了帶寬。總之,你會看到網絡的吞吐量增大了。第二,因為所有被申請的記錄都在用戶的機器上,所以用戶實際上會得到應用程序更佳的總體性能。你可能想把快照的方法限制在較小的數據庫上使用,原因在於快照適用於用戶請求信息而不適用於數據編輯會話。
2、Dynaset(動態集) 使用這個選項時,Visual C++創建指向所請求的每個記錄的實際指針。另外,只有填充屏幕時實際需要的記錄是從服務器上下載來的。這種方法的好處很明顯。幾乎馬上就能在屏幕上看到記錄。而且還會看到其它用戶對數據庫所做的更改。最後,其它用戶也會看到你做的更改,因為動態集在你更改記錄時被上載到服務器上。很明顯,這種方法要求對服務器的實時訪問,它減小了網絡總吞吐量並降低了應用程序的性能。這個選項適合於創建用戶要花費很多時間來編輯數據的應用程序。同時,它也是大型數據庫的最佳選擇,原因在於只需下載用戶實際需要的信息。
3.2 應用ODBC編程
可以應用AppWizard來建立一個ODBC的應用程序框架,也可以直接使用ODBC來進行數據庫編程,這時,應包括頭文件afxdb.h。
應用ODBC編程兩個最重要的類是CDatabase和CRecordSet,但在應用程序中,不應直接使用CRecordSet類,而必須從CRecordSet類產生一個導出類,並添加相應於數據庫表中字段的成員變量。隨後,重載CRecordset類的成員函數DoFieldExchange,該函數通過使用RFX函數完成數據庫字段與記錄集域數據成員變量的數據交換,RFX函數同對話框數據交換(DDX)機制相類似,負責完成數據庫與成員變量間的數據交換。
下面舉例說明在VisualC++環境中ODBC 的編程技巧:
3.21 數據庫連接
在CRecordSet類中定義了一個成員變 量m_pDatabase:
CDatabase *m_pDatabase;
它是指向對象數據庫類的指針。如果在CRecordSet類對象調用Open()函數之前,將一個已經打開的CDatabase類對象指針傳給m_pDatabase,就能共享相同 的CDatabase類對象。如:
CDatabase m_db;
CRecordSet m_set1,m_set2;
m_db.Open(_T("Super_ES")); // 建 立ODBC 連 接
m_set1.m_pDatabase=&m_db; //m_set1 復 用m_db 對 象
m_set2.m_pDatabse=&m_db; // m_set2 復 用m_db 對 象
或如下:
Cdatabase db;
db.Open(“Database”); //建立ODBC連接
CrecordSet m_set(&db); //構造記錄集對象,使數據庫指向db
3.22 查詢記錄
查詢記錄使用CRecordSet::Open()和 CRecordSet::Requery()成員函數。在使用CRecordSet類對象之前,必須使用 CRecordSet::Open()函數來獲得有效的記錄集。一旦已經使用過CRecordSet::Open() 函數,再次查詢時就可以應用CRecordSet::Requery()函數。在調 用CRecordSet::Open()函數時,如果已經將一個已經打開的CDatabase 對象指針傳給CRecordSet類對象的m_pDatabase成員變量,則使 用該數據庫對象建立ODBC連接;否則如果m_pDatabase為空指 針,就新建一個CDatabase類對象並使其與缺省的數據源 相連,然後進行CRecordSet類對象的初始化。缺省數據源 由GetDefaultConnect()函數獲得。你也可以提供你所需要的SQL 語句,並以它來調用CRecordSet::Open()函數,例如:
m_Set.Open(AFX_DATABASE_USE_DEFAULT,strSQL);
如果沒有指定參數,程序則使 用缺省的SQL語句,即對在GetDefaultSQL()函數中指定的SQL語 句進行操作:
CString CTestRecordSet::GetDefaultSQL()
{return _T("[BasicData],[MainSize]");}
對於GetDefaultSQL()函數返回的表名, 對應的缺省操作是SELECT語句,即:
SELECT * FROM BasicData,MainSize
查詢過程中也可以利用CRecordSet的 成員變量m_strFilter和m_strSort來執行條件查詢和結果排序。m_strFilter 為過濾字符串,存放著SQL語句中WHERE後的條件串;m_strSort 為排序字符串,存放著SQL語句中ORDERBY後的字符串。 如:
m_Set.m_strFilter="TYPE=電動機";
m_Set.m_strSort="VOLTAGE";
m_Set.Requery();
對應的SQL語句為:
SELECT * FROM BasicData,MainSize
WHERE TYPE=電動機
ORDER BY VOLTAGE
除了直接賦值給m_strFilter以外,還 可以使用參數化。利用參數化可以更直觀,更方便地 完成條件查詢任務。使用參數化的步驟如下:
(1).聲明參變量:
Cstring p1;
Float p2;
(2).在構造函數中初始化參變量
p1=_T("");
p2=0.0f;
m_nParams=2;
(3).將參變量與對應列綁定
pFX->SetFieldType(CFieldExchange::param)
RFX_Text(pFX,_T("P1"),p1);
RFX_Single(pFX,_T("P2"),p2);
完成以上步驟之後就可以利用 參變量進行條件查詢了:
m_pSet->m_strFilter="TYPE=?ANDVOLTAGE=?";
m_pSet->p1="電動機";
m_pSet->p2=60.0;
m_pSet->Requery();
參變量的值按綁定的順序替換 查詢字串中的“?”適配符。
如果查詢的結果是多條記錄的 話,可以用CRecordSet類的函數Move(),MoveNext(),MovePrev(),MoveFirst() 和MoveLast()來移動光標。
3.23 增加記錄
增加記錄使用AddNew()函數,要求數據庫必須是以允許增加的方式打開:
m_pSet->AddNew(); //在表的末尾增加新記錄
m_pSet->SetFieldNull(&(m_pSet->m_type),FALSE);
m_pSet->m_type="電動機";
... //輸入新的字段值
m_pSet-> Update(); //將新記錄存入數據庫
m_pSet->Requery(); //重建記錄集
3.24 刪除記錄
直接使用Delete()函數,並且在調用Delete() 函數之後不需調用Update()函數:
m_pSet->Delete();
if(!m_pSet->IsEOF())
m_pSet->MoveNext();
else
m_pSet->MoveLast();
3.25 修改記錄
修改記錄使用Edit()函數:
m_pSet->Edit(); //修改當前記錄
m_pSet->m_type="發電機"; //修改當前記錄字段值
...
m_pSet->Update(); //將修改結果存入數據庫
m_pSet->Requery();
3.26 統計記錄
統計記錄用來統計記錄集的總數。可以先聲明一個CRecordse