MFC 的 CDatabase 和 CRecordset 類別雖然功能完整,但在處理多資料表應用時,類別精靈會產生大量記錄集原始碼檔案,導致專案結構臃腫混亂。本文介紹的 CDataSet 模板類別,旨在減少程式碼數量,同時增強記錄集功能,為資料物件陣列提供統一介面。
CDataSet 採用雙參數模板設計:
template <class T, int M>
class CDataSet : public CRecordset {
public:
CDataSet(LPCSTR Table, CDatabase* pdb);
T m_Data; // 連結的資料物件
CString m_DefaultSQL; // 預設 SQL SELECT 陳述式
CString m_DefaultSort; // 預設 ORDER BY 子句
CString m_DefaultFilter; // 預設 WHERE 子句
// 核心操作方法
virtual BOOL Search(LPCSTR Filter, LPCSTR Sort = NULL, BOOL bFail = FALSE);
virtual BOOL DirectSearch(LPCSTR Filter, LPCSTR Sort = NULL, BOOL bFail = FALSE);
virtual void LoadAll(CArray<T, T>& A, int N = 0);
virtual void SaveAll(CArray<T, T>& A);
virtual void Load(T& Data) { Data = m_Data; }
virtual void Store(T& Data);
// ...
};
m_DefaultSQL 可為資料表名、資料表清單或複雜 SQL 陳述式,且可在執行期動態修改,使相同類別能存取結構相同的不同資料表。
LoadAll():批次載入記錄至陣列,N 參數限制最大筆數SaveAll():批次寫入陣列資料至資料庫Load()/Store():單筆資料的載入與儲存Search():使用預設排序與篩選,找不到且 bFail=TRUE 時拋出例外DirectSearch():接受外部指定的 WHERE 子句,支援動態查詢多數方法呼叫 SetStatus() 顯示沙漏游標與狀態列訊息,處理大量資料時特別有用:
void SetStatus(const CString Msg) {
CFrameWnd* pMainFrame = (CFrameWnd*)AfxGetMainWnd();
if (pMainFrame) {
pMainFrame->SetMessageText(Msg);
pMainFrame->UpdateWindow();
if (strcmp(Msg, "Ready") == 0)
pMainFrame->EndWaitCursor();
else
pMainFrame->BeginWaitCursor();
}
}
CMyException 繼承自 CException,提供自訂錯誤訊息功能,配合 THROW 宏使用。
// 定義資料物件結構
struct DataObj {
CString Var1;
CString Var2;
int Var3;
float Var4;
};
// 實作 DoFieldExchange 建立欄位對應
void CDataSet<DataObj, 4>::DoFieldExchange(CFieldExchange* pFX) {
pFX->SetFieldType(CFieldExchange::outputColumn);
RFX_Text(pFX, "VAR1", m_Data.Var1);
RFX_Text(pFX, "VAR2", m_Data.Var2);
RFX_Int(pFX, "VAR3", m_Data.Var3);
RFX_Single(pFX, "VAR4", m_Data.Var4);
}
// 應用程式中使用
CDatabase db;
CArray<DataObj, DataObj> A;
TRY {
db.Open("TEST");
CDataSet<DataObj, 4> MySet("Table1", &db);
MySet.m_DefaultFilter = "Var1 = '%s'";
MySet.Open();
MySet.LoadAll(A); // 載入所有記錄
if (MySet.Search("Anything")) { // 搜尋特定記錄
DataObj B;
MySet.Load(B);
B.Var1 = "Anything else?";
MySet.Store(B); // 更新記錄
}
MySet.Close();
} CATCH_ALL(e) { e->ReportError(); } END_CATCH_ALL
CDataSet 透過模板機制大幅減少樣板程式碼,統一了資料存取介面,並提供批次操作、動態 SQL、強化搜尋等實用功能,是 MFC 多資料表應用開發的有力工具。