MFC ODBC 編程 1 了解 MFC ODBC MFC 對 ODBC 的封裝主要是開發(fā)了CDatabase 類和 CRecordSet 類。 CDatabase類主要是為了建立應(yīng)用程序和數(shù)據(jù)源的連接功能。 CRecordSet類主要是對數(shù)據(jù)集的操作。 記錄的查詢:主要使用CRecordSet類的Open()方法和Requery()成員函數(shù)。在使用CRecordSet的類對象之前,必須使用CRecordSet的成員函數(shù)Open()來獲得有效的記錄集。一旦使用過Open()函數(shù),再次查詢時使用Requery()函數(shù)就可以了。 記錄的添加:只用AddNew()函數(shù),不過必須保證在數(shù)據(jù)庫是在允許添加的模式打開的。 記錄的刪除:調(diào)用Delete()函數(shù)完成,在使用完Delete()函數(shù)之后不用調(diào)用Update()函數(shù)了。 記錄的修改:調(diào)用Edit()函數(shù)完成,在使用過Edit()函數(shù)之后需要調(diào)用Update()函數(shù)將修改結(jié)果存入數(shù)據(jù)庫。 撤銷數(shù)據(jù)庫更新操作:如果在增加、刪除或者編輯記錄之后,想撤銷原來的操作,應(yīng)該在Update()函數(shù)之前使用Move()函數(shù)。CRecordSet::Move(AFX_MOVE_REFRESH); 該函數(shù)用于撤消增加或修改模式,并恢復(fù)在增加或修改模式之前的當(dāng)前記錄。其中參 數(shù)AFX_MOVE_REFRESH的值為零。 直接執(zhí)行SQL操作:這個需要調(diào)用CDatabase類的ExecuteSQL()函數(shù)。需要注意的是,由于不同DBMS提供的數(shù)據(jù)操作語句不盡相同,直接執(zhí)行SQL語句可能會破壞軟件的DBMS無關(guān)性,因此在應(yīng)用中應(yīng)當(dāng)慎用此類操作。 MFC ODBC的數(shù)據(jù)庫操作過程: 首先,應(yīng)用程序應(yīng)該先使用CDatabase類的Open()函數(shù)實現(xiàn)與ODBC數(shù)據(jù)源的連接,然后傳遞CDatabase類的指針到CRecordSet類的構(gòu)造函數(shù)中,使CRecordSet對象與原來的數(shù)據(jù)源結(jié)合起來。完成了數(shù)據(jù)源的連接之后,大量的操作集中在數(shù)據(jù)集之上。完成操作之后,先關(guān)閉所有記錄集的連接,然后關(guān)閉數(shù)據(jù)源的連接。 1.1 CDatabase 類 CDatabase 類用于應(yīng)用程序建立同數(shù)據(jù)源的連接。CDatabase 類包含一個 m_hdbc 變量,它代表了數(shù)據(jù)源的連接句柄。如果要建立 CDatabase 類的實例,應(yīng)先調(diào)用該類的構(gòu)造函數(shù),再調(diào)用 Open 函數(shù),通過調(diào)用,初始化環(huán)境變量,并執(zhí)行與數(shù)據(jù)源的連接。關(guān)閉數(shù)據(jù)源連接的函數(shù)是Close。 CDatabase 類提供了對數(shù)據(jù)庫進(jìn)行操作的函數(shù),為了執(zhí)行事務(wù)操作,CDatabase 類提供了 BeginTrans函數(shù),當(dāng)全部數(shù)據(jù)都處理完成后,可以通過調(diào)用CommitTrans函數(shù)提交事務(wù), 或者在特殊情況下通過調(diào)用Rollback函數(shù)將處理回退。 CDatabase 類提供的函數(shù)可以用于返回數(shù)據(jù)源的特定信息, 例如通過GetConnect函數(shù)返回在使用函數(shù)Open連接數(shù)據(jù)源時的連接字符串,通過調(diào)用IsOpen 函數(shù)返回當(dāng)前的CDatabase 實例是否已經(jīng)連接到數(shù)據(jù)源上,通過調(diào)用 CanUpdate 函數(shù)返回當(dāng)前的CDatabase 實例是否是可更新的, 通過調(diào)用CanTransact函數(shù)返回當(dāng)前的 CDatabase 實例是否支持事務(wù)操作,等等。 總之,CDatabase 類為 C++數(shù)據(jù)庫開發(fā)人員提供了ODBC 的面向?qū)ο蟮木幊探涌凇?/span> 1.2 CRecordSet 類 CRecordSet 類實現(xiàn)對結(jié)果集的數(shù)據(jù)操作。CRecordSet 類定義了從數(shù)據(jù)庫接收或者發(fā)送數(shù)據(jù)到數(shù)據(jù)庫的成員變量,CRecordSet 類定義的記錄集可以是表的所有列,也可以是其中的一列,這是由 SQL語句決定的。 CRecordSet 類的成員變量m_hstmt 代表了定義該記錄集的SQL 語句句柄,m_nFields成員變量保存了記錄集中字段的個數(shù),m_nParams 成員變量保存了記錄集所使用的參數(shù)個數(shù)。 CRecordSet 的記錄集通過CDatabase 實例的指針實現(xiàn)同數(shù)據(jù)源的連接,即CRecordSet 的成員變量m_pDatabase。 如果記錄集使用了WHERE 子句,m_strFilter 成員變量將保存記錄集的WHERE 子句的內(nèi)容, 如果記錄集使用了 ORDER BY 子句,m_strSort 成員變量將保存記錄集的ORDER BY 子句的內(nèi)容。 由多種方法可以打開記錄集, 最常用的方法是使用Open 函數(shù)執(zhí)行一個SQL SELECT 語句。 有如下四種類型的記錄集: • CRecordset::dynaset: 動態(tài)記錄集, 支持雙向游標(biāo), 并保持同所連接的數(shù)據(jù)源同步, 對數(shù)據(jù)的更新操作可以通過一個fetch操作獲取。 • CRecordset::snapshot: 靜態(tài)快照,一旦形成記錄集,此后數(shù)據(jù)源的所有改變都不能體現(xiàn)在記錄集里,應(yīng)用程序必須重新進(jìn)行查詢,才能獲取對數(shù)據(jù)的更新。該類型記錄集也支持雙向游標(biāo)。 • CRecordset::dynamic: 同 CRecordset::dynaset記錄集相比,CRecordset::dynamic記錄還能在 fetch 操作里同步其它用戶對數(shù)據(jù)的重新排序。 • CRecordset::forwardOnly: 除了不支持逆向游標(biāo)外,其它特征同CRecordset::snapshot相同。 6.2 MFC ODBC 數(shù)據(jù)庫訪問技術(shù) 2.1 記錄查詢 使用 CRecordSet 的 Open()和 Requery()成員函數(shù)可以實現(xiàn)記錄查詢。需要注意的是,在使用CRecordSet 的類對象之前, 必須使用CRecordSet 的成員函數(shù)Open()來獲得有效的記錄集。 一旦使用過Open()函數(shù), 再次查詢時使用 Requery()函數(shù)就可以了。 在調(diào)用Open()函數(shù)時, 如果已經(jīng)將一個打開的CDatabase 對象指針傳遞給 CRecordSet類對象的m_pDatabase成員變量, 那么, CRecordSet類對象將使用該數(shù)據(jù)庫對象建立ODBC連接;否則,如果m_pDatabase為空指針,對象就需要就新建一個CDatabase 類對象并使其與缺省的數(shù)據(jù)源相連,然后進(jìn)行CRecordSet 類對象的初始化。缺省數(shù)據(jù)源由GetDefaultConnect()函數(shù)獲得。也可以通過特定的 SQL 語句為 CRecordSet 類對象指定數(shù)據(jù)源,并以它來調(diào)用CRecordSet 類的 Open()函數(shù),例如: myRS.Open(AFX_DATABASE_USE_DEFAULT,strSQL); 如果沒有指定參數(shù), 程序則使用缺省的SQL 語句, 即對在GetDefaultSQL()函數(shù)中指定的SQL 語句進(jìn)行操作,代碼如下: CString CMyRS::GetDefaultSQL() {return_T("[Name],[Age]");} 對于 GetDefaultSQL()函數(shù)返回的表名,對應(yīng)的缺省操作是SELECT 語句,例如: SELECT * FROM BasicData,MainSize 在查詢過程中,也可以利用CRecordSet 類的成員變量m_strFilter 和 m_strSort 來執(zhí)行條件查詢和結(jié)果排序。m_strFilter 用于指定過濾字符串,存放著SQL 語句中關(guān)鍵字WHERE 后的條件語句;m_strSort 用于指定用于排序的字符串,存放著SQL 語句中關(guān)鍵字ORDER BY 后的字符串。例如: myRS.m_strFilter="Name='劉鵬'"; myRS.m_strSort="Age"; myRS.Requery(); 數(shù)據(jù)庫查詢中對應(yīng)的SQL 語句為: SELECT * FROM BasicData WHERE Name='劉鵬' ORDER BY Age 除了直接賦值給成員變量m_strFilter 以外, 還可以通過參數(shù)化實現(xiàn)條件查詢。 利用參化可以更直觀、更方便地完成條件查詢?nèi)蝿?wù)。參數(shù)化方法的步驟如下: (1) 聲明參變量,代碼如下: CString strName; int nAge; (2) 在構(gòu)造函數(shù)中初始化參變量如下: strName =_T(""); nAge =0; m_nParams=2; (3) 將參變量與對應(yīng)列綁定,代碼如下: pFX->SetFieldType(CFieldExchange::param) RFX_Text(pFX,_T("Name"), strName); RFX_Single(pFX,_T("Age"), nAge); 完成以上步驟之后就可以利用參變量進(jìn)行條件查詢了,代碼如下: m_pmyRS->m_strFilter="Name=? AND age=?"; m_ pmyRS -> strName ="劉鵬"; m_ pmyRS ->nAge=26; m_ pmyRS ->Requery(); 參變量的值按綁定的順序替換查詢字串中的“?”通配符。 如果查詢的結(jié)果是多條記錄,可以利用CRecordSet 類的成員函數(shù)Move(),MoveNext(),MovePrev(),MoveFirst()和MoveLast()來移動記錄光標(biāo)。 2.2 記錄添加 使用 AddNew()成員函數(shù)能夠?qū)崿F(xiàn)記錄添加,需要注意的是,在記錄添加之前必須保證數(shù)據(jù)庫是以允許添加的方式打開的,需要調(diào)用Update()更新,代碼如下: m_ pmyRS ->AddNew(); // 在表的末尾添加新記錄 m_ pmyRS ->SetFieldNull(&(m_pSet->m_type),FALSE); m_pmyRS->m_strName=”劉鵬”; //輸入新的字段值 m_ pmyRS ->m_nAge=26; // 輸入新的字段值 m_ pmyRS ->Update(); // 將新記錄存入數(shù)據(jù)庫 m_ pmyRS ->Requery(); // 重新建立記錄集 2.3 記錄刪除 調(diào)用 Delete()成員函數(shù)能夠?qū)崿F(xiàn)記錄刪除,在調(diào)用Delete()函數(shù)后不需調(diào)用Update()函數(shù),代碼如下: m_pmyRS ->Delete(); if(!m_ pmyRS ->IsEOF()) m_ pmyRS ->MoveNext(); else m_ pmyRS ->MoveLast(); 2.4 記錄修改 調(diào)用 Edit()成員函數(shù)可以實現(xiàn)記錄修改, 在修改完成后需要調(diào)用Update()將修改結(jié)果存入數(shù)據(jù)庫, 代碼如下: m_ pmyRS ->Edit(); m_ pmyRS ->m_strName="劉波"; // 修改當(dāng)前記錄字段值 ... m_ pmyRS ->Update(); m_pmyRS->Requerey(); 2.5 撤銷數(shù)據(jù)庫更新操作 如果用戶增加或者修改記錄后希望放棄當(dāng)前操作,可以在調(diào)用Update()函數(shù)之前調(diào) 用 Move()函數(shù),就可以使數(shù)據(jù)庫更新撤銷了,代碼如下: CRecordSet::Move(AFX_MOVE_REFRESH); 該函數(shù)用于撤消增加或修改模式,并恢復(fù)在增加或修改模式之前的當(dāng)前記錄。其中AFX_MOVE_REFRESH的值為零。 2.6 直接執(zhí)行 SQL 語句 雖然通過 CRecordSet 類我們可以完成大多數(shù)的數(shù)據(jù)庫查詢操作,而且在CRecordSet 類的 Open()成員函數(shù)中也可以提供SQL 語句,但有的時候我們還想進(jìn)行一些其他操作,例如建立新表、刪除表、建立新的字段等等,這時就需要用到CDatabase 類的直接執(zhí)行SQL 語句的機制。 通過調(diào)用CDatabase 類的 ExecuteSQL()成員函數(shù)就能夠完成SQL 語句的直接執(zhí)行,代碼如下: BOOL CMyDB::ExecuteSQLWithReport (const CString& strSQL) { TRY { m_pMyDB->ExecuteSQL(strSQL); // 直接執(zhí)行 SQL 語句 } CATCH(CDBException,e) { CString strMsg; strMsg.LoadString(IDS_EXECUTE_SQL_FAILED); strMsg+=strSQL; return FALSE; } END_CATCH return TRUE; } 需要注意的是,由于不同DBMS 提供的數(shù)據(jù)操作語句不盡相同,直接執(zhí)行SQL 語句可能會破壞軟件的DBMS 無關(guān)性,因此在應(yīng)用中應(yīng)當(dāng)慎用此類操作。 2.7 MFC ODBC 的數(shù)據(jù)庫操作過程 ODBC API編程類似,MFC的ODBC編程也要先建立同ODBC 數(shù)據(jù)源的連接,這個過程由一個CDatabase對象的Open函數(shù)實現(xiàn)。然后CDatabase對象的指針將被傳遞到CRecordSet對象的構(gòu)造函數(shù)里,使CRecordSet 對象與當(dāng)前建立起來的數(shù)據(jù)源連接結(jié)合起來。 完成數(shù)據(jù)源連接之后, 大量的數(shù)據(jù)庫編程操作將集中在記錄集的CRecordSet 類操作上。在應(yīng)用程序退出運行狀態(tài)的時候, 需要將所有的記錄集關(guān)閉,并關(guān)閉所有同數(shù)據(jù)源的連接。 3 本 章 小 結(jié) 本章介紹了 MFC ODBC 編程方法和過程。與ODBC API 編程相比,MFC 編程更適用于界面型數(shù)據(jù)庫應(yīng)用程序的開發(fā),由于MFC 的廣泛支持,ODBC 編程可以對數(shù)據(jù)進(jìn)行很好地表示。 然而MFC 的 CDatabase 類和 CRecordset類提供的數(shù)據(jù)庫操作函數(shù)非常有限,支持的游標(biāo)類型也很有限,限制了高效的數(shù)據(jù)庫開發(fā)。 從編程層次上,ODBC 的 MFC 編程則屬于高級編程。 參考《VC++數(shù)據(jù)庫編程》
|
|