承接上集內容,本文將深入剖析 CAdoRecordSet 類的核心方法與屬性,涵蓋記錄集操作、欄位存取、游標控制、批次更新、書籤導航、Blob 處理等進階主題。所有程式碼片段均取自實際專案,經過重構與註解優化,適合直接套用至生產環境。
CAdoRecordSet::CAdoRecordSet();
CAdoRecordSet::CAdoRecordSet(CAdoConnection *pConnection);
void CAdoRecordSet::SetAdoConnection(CAdoConnection *pConnection);
建構子支援預設建構與帶連線指標建構兩種模式。SetAdoConnection 用於在記錄集建立後動態綁定 CAdoConnection 實例,實現連線物件的複用與解耦。
BOOL CAdoRecordSet::Open(LPCTSTR strSQL, long lOption,
CursorTypeEnum CursorType, LockTypeEnum LockType);
| 參數 | 說明 |
|---|---|
| strSQL | SQL 指令、資料表名、預存程序或持久化 Recordset 檔案路徑 |
| lOption | 指定 strSQL 類型:adCmdText(預設)、adCmdTable、adCmdStoredProc、adCmdFile、adAsyncExecute 等 |
| CursorType | 游標類型:adOpenForwardOnly、adOpenKeyset、adOpenDynamic、adOpenStatic |
| LockType | 鎖定模式:adLockReadOnly、adLockPessimistic、adLockOptimistic、adLockBatchOptimistic |
實戰範例:
if (m_adoConnection.OpenUDLFile(_T("C:\\mm.udl"))) {
m_adoRecordSet.SetAdoConnection(&m_adoConnection);
m_adoRecordSet.SetCursorLocation(adUseClient); // 客戶端游標支援斷線操作
m_adoRecordSet.Open(_T("ado"), adCmdTable); // 直接開啟資料表
// 交易式新增資料
m_adoConnection.BeginTrans();
bool bSex = (m_strSex == _T("男"));
m_adoRecordSet.AddNew();
bool bOk = m_adoRecordSet.PutCollect(_T("age"), m_nAge)
&& m_adoRecordSet.PutCollect(_T("length"), m_fLength)
&& m_adoRecordSet.PutCollect(_T("name"), m_strName)
&& m_adoRecordSet.PutCollect(_T("tel"), m_strTel)
&& m_adoRecordSet.PutCollect(_T("money"), m_cyMoney)
&& m_adoRecordSet.PutCollect(_T("date"), m_dtDate)
&& m_adoRecordSet.PutCollect(_T("sex"), bSex);
if (!bOk) {
m_adoRecordSet.CancelUpdate();
m_adoConnection.RollbackTrans();
} else {
m_adoRecordSet.Update();
m_adoConnection.CommitTrans();
}
// 清理編輯狀態
if (m_adoRecordSet.GetEditMode() != adEditNone)
m_adoRecordSet.CancelUpdate();
m_adoRecordSet.Close();
}
AddNew():啟動新增模式,游標移至暫存緩衝區Update():提交新增或修改至資料來源CancelUpdate():放棄尚未 Update 的變更,游標回到原記錄BOOL UpdateBatch(AffectEnum AffectRecords = adAffectAll);
BOOL CancelBatch(AffectEnum AffectRecords = adAffectAll);
僅支援 Keyset 或 Static 游標。AffectRecords 可控制影響範圍:adAffectCurrent、adAffectGroup、adAffectAll、adAffectAllChapters。
BOOL Delete(AffectEnum AffectRecords = adAffectCurrent);
同樣支援多種影響範圍常數,搭配 Filter 屬性可實現條件式批次刪除。
封裝類提供豐富的重載,支援索引與欄位名兩種存取方式,並自動處理 _variant_t、CString、數值型別、COleDateTime、COleCurrency 等轉換:
BOOL PutCollect(LPCTSTR strFieldName, const CString &value);
BOOL PutCollect(LPCTSTR strFieldName, const COleDateTime &value);
BOOL GetCollect(LPCTSTR strFieldName, CString &strValue);
BOOL GetCollect(LPCTSTR strFieldName, COleDateTime &value);
// ... 其餘數值型別重載略
特色:若資料庫欄位為數字字串,可直接以 long 或 double 讀取,封裝層自動完成型別轉換。
| 方法 | 行為 | 適用場景 |
|---|---|---|
| Requery | 重新執行原始查詢,等同 Close+Open | 需看見新增記錄、結構變更 |
| Resync | 僅同步現有記錄與資料庫最新值 | 靜態/唯向前游標,效能較佳 |
Resync 不會重新執行命令,因此無法看見他人新增的記錄;若 CursorLocation=adUseClient,僅非唯讀 Recordset 可用。
BOOL Save(LPCTSTR strFileName, PersistFormatEnum PersistFormat = adPersistXML);
BOOL Load(LPCTSTR strFileName);
支援 adPersistADTG (二進位) 與 adPersistXML (預設) 兩種格式。Filter 生效時僅儲存篩選後的列。
MoveFirst/Last/Next/Previous:基本游標移動Move(lRecords, Start):相對移動,Start 可為 adBookmarkCurrent/First/LastFind/FindFirst:條件查找,支援 SearchDirectionEnumSetFilter/GetFilter:動態篩選,如 Name <> 'anyou' And Age > 20SetSort:排序,如 Name DESC, Age ASCvoid GetBookmark(); // 取得目前記錄書籤
BOOL SetBookmark(); // 移動至書籤記錄
BOOL Clone(CAdoRecordSet &pRecordSet); // 建立複本,獨立游標
Clone 後的 Recordset 關閉互不影響,適合多視圖同步顯示同一資料集。
BOOL AppendChunk(LPCTSTR strFieldName, LPCTSTR lpszFileName); // 直接寫入檔案
BOOL GetChunk(LPCTSTR strFieldName, CBitmap &bitmap); // 讀取圖片
寫入範例:
m_adoRecordSet.AddNew();
m_adoRecordSet.SetFieldValue(_T("ID"), 5);
m_adoRecordSet.AppendChunk(_T("Document"), _T("C:\\doc1.txt"));
m_adoRecordSet.Update();
讀取範例:
long size = GetFieldActualSize(strFieldName);
if ((adFldLong & GetFieldAttributes(strFieldName)) && size > 0) {
BYTE *lpData = new BYTE[size];
if (GetChunk(GetField(strFieldName), (LPVOID)lpData)) {
// 處理二進位資料
}
delete[] lpData;
}
| 方法 | 用途 |
|---|---|
| GetFieldName / GetFields / GetField | 取得欄位名稱、集合、單一欄位物件 |
| GetFieldAttributes | 欄位屬性:adFldUpdatable、adFldIsNullable、adFldLong 等 |
| GetFieldDefineSize / GetFieldActualSize | 定義長度 vs 實際長度 |
| GetFieldType | 資料型別:adVarChar、adInteger、adDate、adLongVarBinary 等 |
| IsFieldNull | 快速判斷 Null 值 |
GetState():adStateOpen、adStateExecuting、adStateFetching 等位元組合GetStatus():批次更新狀態,adRecOK、adRecNew、adRecModified、adRecDeleted 等GetRecordCount()、GetFieldsCount()、IsBOF()、IsEOF()GetEditMode():adEditNone、adEditInProgress、adEditAdd、adEditDeleteif (m_adoConnection.ConnectAccess(_T("database.mdb"))) {
m_adoRecordSet.SetAdoConnection(&m_adoConnection);
m_adoRecordSet.SetCursorLocation(adUseClient); // 必須為客戶端游標
if (m_adoRecordSet.Open(lpszPathName, adCmdTable)) {
m_wndDataGrid.SetRefDataSource(NULL);
m_wndDataGrid.SetRefDataSource((LPUNKNOWN)m_adoRecordSet.GetRecordset());
m_wndDataGrid.SetAllowAddNew(TRUE);
m_wndDataGrid.SetAllowDelete(TRUE);
m_wndDataGrid.SetAllowUpdate(TRUE);
m_wndDataGrid.Refresh();
}
}
關鍵點:必須設定 adUseClient,否則 DataGrid 無法正確繫結。
BOOL Supports(CursorOptionEnum CursorOptions);
常用檢查項:adAddNew、adDelete、adUpdate、adBookmark、adMovePrevious、adUpdateBatch、adSeek。注意:回傳 True 僅代表提供者支援該功能,不保證所有情境下皆可用(如多表 Join 的更新限制)。