直接通過ADO操作Access數據庫(修改版)

本文根據VCKBASE網站的上的《直接通過ADO操作Access數據庫 》 修改而來,版權歸原作者/徐景周

直接通過ADO操作Access數據庫 


作者/徐景周

下載源代 碼 

    我在《VC知識庫在線雜誌》第十四期和第十五期上曾發表了兩篇文章——“直接通過ODBC讀、寫Excel表格文件 ”和“直接通過DAO讀、寫Access文件 ”,先後給大家介紹了ODBC和DAO兩種數據庫訪問技術的基本使用方 法,這次要給大家介紹的是ADO數據庫訪問技術的使用方法。ADO(Active Data Object,活動數據對象)實際上是一種基於COM(組件對象模型)的自動化接口(IDispatch)技術,並以OLE DB(對象連接和鑲入的數據庫)爲基礎,經過OLE DB精心包裝後的數據庫訪問技術,利用它可以快速的創建數據庫應用程序。 ADO提供了一組非常簡單,將一般通用的數據訪問細節進行封裝的對象。由於ODBC數據源也提供了一般的OLE DB Privider,所以ADO不僅可以應用自身的OLE DB Privider,而且還可以應用所有的ODBC驅動程序。關於OLE DB和ADO的其它詳細情況,讀者可以自行查閱相關書籍或MSDN,這裏就不一一說明了。讓我們直接步入主題:如何掌握ADO這種數據庫訪問技術。ADO 的操作方法和前面講過的DAO的操作在很多方面存在相似之處,在這裏,筆者爲了更有效的說明它的使用方法,用VC6.0做了一個示例程序—— AdoRWAccess,這個示例程序可以直接通過ADO來操作Access數據庫,示例程序的運行效果如下圖所示:

 

在示例程序中我們仍採用原庫結構,數據庫名Demo.mdb,庫內表名DemoTable,表內字段名爲Name(姓名)和Age(年齡)的兩個字 段,來構造示例程序操作所需的Access數據庫,這也和上兩篇文章的示例源碼中的庫結構相兼容。
下面讓我們看看ADO數據庫訪問技術使用的基本步驟及方法:
    首先,要用#import語句來引用支持ADO的組件類型庫(*.tlb),其中類型庫可以作爲可執行程序(DLL、EXE等)的一部分被定位在其自身程 序中的附屬資源裏,如:被定位在msado15.dll的附屬資源中,只需要直接用#import引用它既可。可以直接在Stdafx.h文件中加入下面 語句來實現:

  1. // 加入ADO支持庫, jingzhou xu  
  2. #import "c:/program files/common files/system/ado/msado15.dll" /  
  3.     no_namespace /  
  4.     rename ("EOF""adoEOF")      

其中路徑名可以根據自己系統安裝的ADO支持文件的路徑來自行設定。當編譯器遇到#import語句時,它會爲引用組件類型庫中的接口生成包裝 類,#import語句實際上相當於執行了API涵數LoadTypeLib()。#import語句會在工程可執行程序輸出目錄中產生兩個文件,分別 爲*.tlh(類型庫頭文件)及*.tli(類型庫實現文件),它們分別爲每一個接口產生智能指針,併爲各種接口方法、枚舉類型,CLSID等進行聲明, 創建一系列包裝方法。語句no_namespace說明ADO對象不使用命名空間,rename ("EOF", "adoEOF")說明將ADO中結束標誌EOF改爲adoEOF,以避免和其它庫中命名相沖突。
    其次,在程序初始過程中需要初始化組件,一般可以用CoInitialize(NULL);來實現,這種方法在結束時要關閉初始化的COM,可以用下面語 句CoUnInitialize();來實現。在MFC中還可以採用另一種方法來實現初始化COM,這種方法只需要一條語句便可以自動爲我們實現初始化 COM和結束時關閉COM的操作,語句如下所示: AfxOleInit();
    接着,就可以直接使用ADO的操作了。我們經常使用的只是前面用#import語句引用類型庫時,生成的包裝類.tlh中聲明的智能指針中的三個,它們分 別是_ConnectionPtr、_RecordsetPtr和_CommandPtr。下面分別對它們的使用方法進行介紹

    在介紹前我們先寫個函數,本例中添加爲類變量的靜態函數

  1. //打印調用ADO控件時產生的詳細錯誤信息  
  2. void CAdoRWAccessDlg::dump_com_error(_com_error &e)  
  3. {  
  4.     CString ErrorStr;  
  5.     _bstr_t bstrSource(e.Source());  
  6.     _bstr_t bstrDescription(e.Description());  
  7.     ErrorStr.Format( "/n/tADO Error/n/tCode = %08lx/n/tCode meaning = %s/n/tSource = %s/n/tDescription = %s/n/n",  
  8.         e.Error(), e.ErrorMessage(), (LPCTSTR)bstrSource, (LPCTSTR)bstrDescription );  
  9.     //在調試窗口中打印錯誤信息,在Release版中可用DBGView查看錯誤信息  
  10.     ::OutputDebugString((LPCTSTR)ErrorStr);  
  11. #ifdef _DEBUG  
  12.     AfxMessageBox(ErrorStr, MB_OK | MB_ICONERROR);  
  13. #endif    
  14. }  

 

1、_ConnectionPtr智能指針,通常用於打開、關閉一個庫連接或用它的Execute方法來執行一個不返回結果的命令語句(用法和 _CommandPtr中的Execute方法類似)。
——打開一個庫連接。先創建一個實例指針,再用Open打開一個庫連接,它將返回一個IUnknown的自動化接口指針。代碼如下所示:

在CAdoRWAccessApp中添加一個public的成員變量

  1. _ConnectionPtr  m_pConnection;  

在BOOL CAdoRWAccessApp::InitInstance()函數中

  1. // 初始化COM,創建ADO連接等操作  
  2. AfxOleInit();  
  3. m_pConnection.CreateInstance(__uuidof(Connection));  
  4. // 在ADO操作中建議語句中要常用try...catch()來捕獲錯誤信息,  
  5. // 因爲它有時會經常出現一些想不到的錯誤。jingzhou xu  
  6. try                   
  7. {     
  8.     // 打開本地Access庫Demo.mdb  
  9.     m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Demo.mdb","","",adModeUnknown);  
  10.       
  11. }  
  12. catch(_com_error& e)  
  13. {  
  14.     //調用在CAdoRWAccessDlg中打印錯誤信息的靜態函數  
  15.     CAdoRWAccessDlg::dump_com_error(e);  
  16.     return FALSE;  
  17. }  

——關閉一個庫連接(本例中在CAdoRWAccessApp::ExitInstance())。如果連接狀態有效,則用Close方法關閉它並賦於它空值。代碼如下所示:

  1. // 關閉ADO連接狀態  
  2. if(m_pConnection->State)  
  3.     m_pConnection->Close();  
  4. m_pConnection= NULL;  

2、_RecordsetPtr智能指針,可以用來打開庫內數據表,並可以對錶內的記錄、字段等進行各種操作。
——打開數據表。打開庫內表名爲DemoTable的數據表,代碼如下:

添加類成員變量

  1. _RecordsetPtr   m_pRecordset;  

在CAdoRWAccessDlg::OnInitDialog()中

  1. // 使用ADO創建數據庫記錄集  
  2. m_pRecordset.CreateInstance(__uuidof(Recordset));  
  3. // 在ADO操作中建議語句中要常用try...catch()來捕獲錯誤信息,  
  4. // 因爲它有時會經常出現一些想不到的錯誤。jingzhou xu  
  5. try  
  6. {  
  7.     m_pRecordset->Open("SELECT * FROM DemoTable",                // 查詢DemoTable表中所有字段  
  8.                         theApp.m_pConnection.GetInterfacePtr(),  // 獲取庫接庫的IDispatch指針  
  9.                         adOpenDynamic,  
  10.                         adLockOptimistic,  
  11.                         adCmdText);  
  12. }  
  13. catch(_com_error& e)  
  14. {  
  15.     dump_com_error(e);  
  16. }  

——讀取表內數據。將表內數據全部讀出並顯示在列表框內,m_AccessList爲列表框的成員變量名。如果沒有遇到表結束標誌adoEOF,則用 GetCollect(字段名)或m_pRecordset->Fields->GetItem(字段名)->Value方法,來獲取 當前記錄指針所指的字段值,然後再用MoveNext()方法移動到下一條記錄位置。代碼如下所示:

 

  1. _variant_t var;  
  2. CString strName,strAge;  
  3. // 清空列表框  
  4. m_AccessList.ResetContent();  
  5. strName=strAge="";  
  6. // 在ADO操作中建議語句中要常用try...catch()來捕獲錯誤信息,  
  7. // 因爲它有時會經常出現一些想不到的錯誤。jingzhou xu  
  8. try  
  9. {  
  10.     if(!m_pRecordset->BOF)  
  11.         m_pRecordset->MoveFirst();  
  12.     else  
  13.     {  
  14.         AfxMessageBox("表內數據爲空");  
  15.         return;  
  16.     }  
  17.     // 讀入庫中各字段並加入列表框中  
  18.     while(!m_pRecordset->adoEOF)  
  19.     {  
  20.         var = m_pRecordset->GetCollect("Name");  
  21.         if(var.vt != VT_NULL)  
  22.             strName = (LPCSTR)_bstr_t(var);  
  23.         var = m_pRecordset->GetCollect("Age");  
  24.         if(var.vt != VT_NULL)  
  25.             strAge = (LPCSTR)_bstr_t(var);  
  26.         m_AccessList.AddString( strName + " --> "+strAge );  
  27.         m_pRecordset->MoveNext();  
  28.     }  
  29.     // 默認列表指向第一項,同時移動記錄指針並顯示  
  30.     m_AccessList.SetCurSel(0);  
  31.     OnSelchangeListaccess();  
  32. }  
  33. catch(_com_error& e)  
  34. {  
  35.     dump_com_error(e);  
  36. }  
 

——插入記錄。可以先用AddNew()方法新增一個空記錄,再用PutCollect(字段名,值)輸入每個字段的值,最後再Update()更新到庫 中數據既可。其中變量m_Name和m_Age分別爲姓名及年齡編輯框的成員變量名。代碼所下所示:

  1. // 在ADO操作中建議語句中要常用try...catch()來捕獲錯誤信息,  
  2. // 因爲它有時會經常出現一些想不到的錯誤。jingzhou xu  
  3. try  
  4. {  
  5.     // 寫入各字段值  
  6.     m_pRecordset->AddNew();  
  7.     m_pRecordset->PutCollect("Name", _variant_t(m_Name));  
  8.     m_pRecordset->PutCollect("Age", atol(m_Age));  
  9.     m_pRecordset->Update();  
  10.     AfxMessageBox("插入成功!");  
  11.     // 更新顯示其庫內容  
  12.     int nCurSel = m_AccessList.GetCurSel();  
  13.     OnReadAccess();  
  14.     m_AccessList.SetCurSel(nCurSel);  
  15.     // 移動記錄指針到新的位置  
  16.     OnSelchangeListaccess();  
  17. }  
  18. catch(_com_error& e)  
  19. {  
  20.     dump_com_error(e);  
  21. }  

——移動記錄指針。移動記錄指針可以通過MoveFirst()方法移動到第一條記錄、MoveLast()方法移動到最後一條記錄、 MovePrevious()方法移動到當前記錄的前一條記錄、MoveNext()方法移動到當前記錄的下一條記錄。但我們有時經常需要隨意移動記錄指 針到任意記錄位置時,可以使用Move(記錄號)方法來實現,注意: Move()方法是相對於當前記錄來移動指針位置的,正值向後移動、負值向前移動,如:Move(3),當前記錄是3時,它將從記錄3開始往後再移動3條 記錄位置。代碼如下所示:

  1. try  
  2. {  
  3.     int curSel = m_AccessList.GetCurSel();    
  4.     // 先將指針移向第一條記錄,然後就可以相對第一條記錄來隨意移動記錄指針  
  5.     m_pRecordset->MoveFirst();  
  6.     m_pRecordset->Move(long(curSel));  
  7.       
  8. }  
  9. catch(_com_error& e)  
  10. {  
  11.     dump_com_error(e);  
  12. }   

——修改記錄中字段值。可以將記錄指針移動到要修改記錄的位置處,直接用PutCollect(字段名,值)將新值寫入並Update()更新數據庫既 可。可以用上面方法移動記錄指針,修改字段值代碼如下所示:

  1. // 修改當前記錄的字段值  
  2. try  
  3. {  
  4.     m_pRecordset->PutCollect("Name", _variant_t(m_Name));  
  5.     m_pRecordset->PutCollect("Age", atol(m_Age));  
  6.     m_pRecordset->Update();  
  7.     // 重新讀入庫記錄更新顯示  
  8.     int nCurSel = m_AccessList.GetCurSel();  
  9.     OnReadAccess();  
  10.     m_AccessList.SetCurSel(nCurSel);  
  11.     // 移動記錄指針到新的位置  
  12.     OnSelchangeListaccess();  
  13. }  
  14. catch(_com_error& e)  
  15. {  
  16.     dump_com_error(e);  
  17. }  

——刪除記錄。刪除記錄和上面修改記錄的操作類似,先將記錄指針移動到要修改記錄的位置,直接用Delete()方法刪除它並用Update()來更新數 據庫既可。代碼如下所示:

  1. try  
  2. {  
  3.     // 刪除當前行記錄  
  4.     m_pRecordset->Delete(adAffectCurrent);  
  5.     m_pRecordset->Update();  
  6.     // 刪除列表中當前值  
  7.     int nCurSel = m_AccessList.GetCurSel();  
  8.     m_AccessList.DeleteString(nCurSel);  
  9.     if(nCurSel == 0 && (m_AccessList.GetCount() != 0))  
  10.         m_AccessList.SetCurSel(nCurSel);  
  11.     else if(m_AccessList.GetCount() != 0)  
  12.         m_AccessList.SetCurSel(nCurSel-1);  
  13.       
  14.     // 移動記錄指針到新的位置  
  15.     OnSelchangeListaccess();  
  16. }  
  17. catch(_com_error& e)  
  18. {  
  19.     dump_com_error(e);  
  20. }  

——關閉記錄集。直接用Close方法關閉記錄集並賦於其空值。代碼如下所示:

  1. // 關閉記錄集  
  2. if ( m_pRecordset != NULL )  
  3. {  
  4.     m_pRecordset->Close();  
  5.     m_pRecordset.Release();  
  6.     m_pRecordset = NULL;  
  7. }  

3、CommandPtr智能指針,可以使用_ConnectionPtr或_RecordsetPtr來執行任務,定義輸出參數,執行存儲過程或SQL 語句。 
——執行SQL語句。先創建一個_CommandPtr實例指針,再將庫連接和SQL語句做爲參數,執行Execute()方法既可。代碼如下所示:

  1. _CommandPtr     m_pCommand;  
  2. m_pCommand.CreateInstance(__uuidof(Command));  
  3. m_pCommand->ActiveConnection = theApp.m_pConnection;  // 將庫連接賦於它  
  4. m_pCommand->CommandText = _bstr_t((LPCTSTR)m_strCommand);  // SQL語句  
  5. try   
  6. {  
  7.     // 執行SQL語句,返回記錄集,此記錄不能做插入操作  
  8.     // 故爲了不和m_pRecordset相沖突, 放入新定義的m_pRecordset1  
  9.     m_pRecordset1 = m_pCommand->Execute( NULL, NULL, adCmdText);   
  10. }  
  11. catch(_com_error& e)  
  12. {  
  13.     dump_com_error(e);  
  14. }  

——執行存儲過程。執行存儲過程的操作和上面執行SQL語句類似,不同點僅是CommandText參數中不再是SQL語句,而是存儲過程的名字,如 Demo。另一個不同點就是在Execute()中參數由adCmdText(執行SQL語句),改爲adCmdStoredProc來執行存儲過程。如 果存儲過程中存在輸入、輸出參數的話,需要使用到另一個智能指針_ParameterPtr來逐次設置要輸入、輸出的參數信息,並將其賦於 _CommandPtr中Parameters參數來傳遞信息,有興趣的讀者可以自行查找相關書籍或MSDN。執行存儲過程的代碼如下所示:

  1. _CommandPtr     m_pCommand;  
  2. m_pCommand.CreateInstance(__uuidof(Command));  
  3.   m_pCommand->ActiveConnection = m_pConnection;  // 將庫連接賦於它  
  4. m_pCommand->CommandText = "Demo";    
  5.   m_pCommand->Execute(NULL,NULL, adCmdStoredProc);     

最後,如果想知道詳細實現細節的話,可以在下載示例源碼後,仔細查看源碼既可(內有詳細註釋)。 

聯繫方式: 地址:陝西省西安市勞動路2號院六單元  
郵編:710082 
作者EMAIL:[email protected] 
未來工作室(Future Studio)

 

本文僅僅是修改了打印ADO錯誤的地方,使得打印錯誤信息更全面詳細一些(使我想起了我調用每個windows的非void返回值API,總喜歡用GetLastError+FormatMessage打印詳細錯誤出來)。另把CommandPtr部分給加到代碼中了。

 

注:需要拷貝網頁上的代碼點擊代碼上的“copy to clipboard”或者“view plain”(字太小找不到,CTRL+F)

 

後記:個人強烈建議所有的ADO操作都加上try...catch...打印_com_error的詳細錯誤消息,比如本文中的 dump_com_error。


本文地址:http://blog.csdn.net/zyq5945/article/details/5541280

發佈了18 篇原創文章 · 獲贊 27 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章