一、MFC提供的ODBC資料庫類
Visual C++的MFC基底類別庫定義了幾個資料庫類。在利用ODBC編程時,經常要使用到 CDatabase(資料庫類)、CRecordSet(記錄集類)和CRecordView(可視記錄集類)。
CDatabase類對象提供了對資料來源的串連,通過它可以對資料來源進行操作。
CRecordSet類對象提供了從資料來源中提取出的記錄集。CRecordSet對象通常用於兩種形式:動態行集(dynasets)和快照集(snapshots)。動態行集能與其他使用者所做的更改保持同步,快照集則是資料的一個靜態視圖。每種形式在記錄集被開啟時都提供一組記錄,所不同的是,當在一個動態行集裡滾動到一條記錄時,由其他使用者或應用程式中的其他記錄集對該記錄所做的更改會相應地顯示出來。
CRecordView類對象能以控制項的形式顯示資料庫記錄,這個視圖是直接連到一個CRecordSet對象的表視圖。
二、應用ODBC編程
應用Visual C++的AppWizard可以自動產生一個ODBC應用程式架構,步驟是:開啟File菜單的New選項,選取Projects,填入工程名,選擇MFC AppWizard (exe),然後按AppWizard的提示進行操作。
當AppWizard詢問是否包含資料庫支援時,如果想讀寫資料庫,那麼選定Database view with file support;如果想訪問資料庫的資訊而不想寫回所做的改變,那麼選定Database view without file support。
選好資料庫支援之後,Database Source 按鈕會被啟用,選中它去調用Data Options對話方塊。在Database Options對話方塊中會顯示出已向ODBC註冊的資料庫資源,選定所要操作的資料庫,如:Super_ES,單擊OK後出現Select Database Tables對話方塊,其中列舉了選中的資料庫包含的全部表;選擇要操作的表後,單擊OK。在選定了資料庫和資料表之後,就可以按照慣例繼續進行AppWizard操作。
特別需要指出的是:在產生的應用程式架構View類(如:CSuper_ESView)中,包含一個指向CSuper_ESSet對象的指標m_pSet,該指標由AppWizard建立,目的是在視表單和記錄集之間建立聯絡,使得記錄集中的查詢結果能夠很容易地在視表單上顯示出來。
要使程式與資料來源建立聯絡,需用CDateBase::OpenEx()或CDatabase::Open()函數來進行初始化。資料庫物件必須在使用它構造記錄集對象之前初始化。
三、執行個體
1.查詢記錄
查詢記錄使用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()函數,例如:Super_ESSet.Open(AFX_DATABASE_USE_DEFAULT,strSQL);
如果沒有指定參數,程式則使用預設的SQL語句,即對在GetDefaultSQL()函數中指定的SQL語句進行操作:
CString CSuper_ESSet::GetDefaultSQL() {return _T(″[BsicData],[MinSize]″);} |
對於GetDefaultSQL()函數返回的表名,對應的預設操作是SELECT語句,即:
SELECT *FROM BasicData,MainSize |
在查詢過程中,也可以利用CRecordSet的成員變數m_strFilter和m_strSort來執行條件查詢和結果排序。m_strFilter為過濾字串,存放著SQL語句中WHERE後的條件串;m_strSort為排序字串,存放著SQL語句中ORDER BY後的字串。如:
Super_ESSet.m_strFilter=″TYPE=‘電動機’″; Super_ESSet.m_strSort=″VOLTAGE″; Super_ESSet.Requery(); |
對應的SQL語句為:
SELECT *FROM BasicData,MainSize WHERE TYPE=‘電動機’ ORDER BY VOLTAGE |
除了直接賦值給m_strFilter以外,還可以使用參數化。利用參數化可以更直觀、更方便地完成條件查詢任務。使用參數化的步驟如下:
S聲明參變數:
S在建構函式中初始化參變數:
p1=_T(″″); p2=0.0f; m_nParams=2; |
S將參變數與對應資料行繫結:
pFX->SetFieldType(CFieldExchange::param) RFX_Text(pFX,_T(″P1″),p1); RFX_Single(pFX,_T(″P2″),p2); |
完成以上步驟後就可以利用參變數進行條件查詢:
m_pSet->m_strFilter=″TYPE=? AND VOLTAGE=?″;m_pSet->p1=″電動機″; m_pSet->p2=60.0; m_pSet->Requery(); |
參變數的值按綁定的順序替換查詢字串中的“?”萬用字元。
如果查詢的結果是多條記錄,可以用CRecordSet類的函數Move()、MoveNext()、MovePrev()、MoveFirst()和MoveLast()來移動游標。
2.增加記錄
增加記錄使用AddNew()函數,要求資料庫必須是以允許增加的方式開啟:
m_pSet->AddNew(); //在表的末尾增加新記錄 m_pSet->SetFieldNull(&(m_pSet->m_type), FALSE); m_pSet->m_type=″電動機″; …… //輸入新的欄位值 m_pSet->Update(); //將新記錄存入資料庫 m_pSet->Requery(); //重建記錄集 |
3.刪除記錄
可以直接使用Delete()函數來刪除記錄,並且在調用Delete()函數之後不需調用Update()函數:
m_pSet->Delete(); if (!m_pSet->IsEOF()) m_pSet->MoveNext(); else m_pSet->MoveLast(); |
4.修改記錄
修改記錄使用Edit()函數:
m_pSet->Edit(); //修改目前記錄 m_pSet->m_type=″發電機″; //修改目前記錄欄位值 …… m_pSet->Update(); //將修改結果存入資料庫 m_pSet->Requery(); |
5.撤消操作
如果使用者選擇了增加或者修改記錄後希望放棄當前操作,可以在調用Update()函數之前調用:
CRecordSet::Move(AFX_MOVE_REFRESH)來撤消增加或修改模式,並恢複在增加或修改模式之前的目前記錄。其中,參數AFX_MOVE_REFRESH的值為零。
6.資料庫連接的複用
在CRecordSet類中定義了一個成員變數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對象 |
7.SQL語句的直接執行
雖然我們可以通過CRecordSet類完成大多數的查詢操作,而且在CRecordSet::Open()函數中也可以提供SQL語句,但是有時候我們還是希望進行一些其他動作,例如建立新表、刪除表、建立新的欄位等,這時就需要使用CDatabase類直接執行SQL語句的機制。通過調用CDatabase::ExecuteSQL()函數來完成SQL語句的直接執行:
BOOL CDB::ExecuteSQLAndReportFailure(const CString& strSQL) {TRY {m_pdb->ExecuteSQL(strSQL); //直接執行SQL語句} CATCH (CDBException,e) {CString strMsg; strMsg.LoadString(IDS_EXECUTE_SQL_FAILED); strMsg+=strSQL; return FALSE;} END_CATCH return TRUE;} |
應當指出的是,由於不同的DBMS提供的資料動作陳述式不盡相同,直接執行SQL語句可能會破壞軟體的DBMS無關性,因此在應用中應當慎用此類操作。
8.動態串連表
表的動態串連可以利用在調用CRecordSet::Open()函數時指定SQL語句來實現。同一個記錄集對象只能訪問具有相同結構的表,否則查詢結果將無法與變數相對應。
void CDB::ChangeTable() { if (m_pSet->IsOpen()) m_pSet->Close(); switch (m_id) { case 0: m_pSet->Open(AFX_DB_USE_DEFAULT_TYPE,″SELECT * FROM SLOT0″); //串連表SLOT0 m_id=1; break; case 1: m_pSet->Open(AFX_DB_USE_DEFAULT_TYPE,″SELECT * FROM SLOT1″); //串連表SLOT1 m_id=0; break; } } |
9.動態串連資料庫
可以通過賦與CRecordSet類對象參數m_pDatabase來串連不同資料庫的CDatabase對象指標,從而實現動態串連資料庫。
void CDB::ChangeConnect() { CDatabase* pdb=m_pSet->m_pDatabase; pdb->Close(); switch (m_id) { case 0: if (!pdb->Open(_T(″Super_ES″))) //串連資料來源Super_ES { AfxMessageBox(″資料來源Super_ES開啟失敗″,″請檢查相應的ODBC串連″, MB_OK|MB_ICONWARNING); exit(0); } m_id=1; break; case 1: if (!pdb->Open(_T(″Motor″))) //串連資料來源Motor { AfxMessageBox(″資料來源Motor開啟失敗″,″請檢查相應的ODBC串連″, MB_OK|MB_ICONWARNING); exit(0); } m_id=0; break; } } |
總結:
Visual C++中的ODBC類庫可以協助程式員完成絕大多數的資料庫操作。利用ODBC技術使得程式員從具體的DBMS中解脫出來,從而可以減少軟體開發的工作量,縮短開發週期,並提高效率和軟體的可靠性。