ADO(Active Data Object)是Microsoft提供的一種物件導向,與語言無關的資料訪問應用編程介面。是一種基於COM(元件物件模型)的自動化介面技術,
並以OLE DB(對象串連和嵌入的資料庫)為基礎,經過OLE DB精心封裝後的資料庫訪問技術,利用它可以快速的建立資料庫應用程式。
ADO資料庫訪問的實現步驟:
1. 用#import語句引用支援ADO的組件類型庫(*.tlb),其中類型庫可以作為可執行程式(DLL、EXE等)的一部分被定位在其自身程式中的附屬資源裡。
在Stdafx.h標頭檔中運入msado15.dll #import "c:\program files\common files\system\ado\msado15.dll" \no_namespace \rename ("EOF", "adoEOF")
其路徑可以根據自己系統安裝ADO支援檔案的路徑來自行設定,但是預設都是這個路徑。
2. 初始化COM,由於ADO使用了COM,所以在使用ADO之前,必須對COM進行初始化,否則無法使用。對於初始化有以下兩種方法。
(1). AfxOleInit(),但是只能初始化一次,不能多次調用該函數;
(2). COInitialize(NULL),這種方式在結束時要關閉初始化的COM,可用CoUnInitialize()來關閉COM。
3. 串連資料庫:ADO使用Connection對象來建立與資料庫伺服器的串連。注意:Connection對象的Open()方法的連接字串必須是BSTR或_bstr_t類型。
(1)利用Connection對象的Execute方法執行SQL命令
Execute()方法的原型如下所示:
_RecordsetPtr Connection15::Execute ( _bstr_t CommandText, VARIANT * RecordsAffected, long Options )
其中CommandText是命令字串,通常是SQL命令。參數RecordsAffected是操作完成後所影響的行數, 參數Options表示CommandText中內容的類型,
Options可以取如下值之一:
adCmdText表明CommandText是文本命令;
adCmdTable表明CommandText是一個表名;
adCmdProc表明CommandText是一個預存程序;
adCmdUnknown表明CommandText內容未知。
Execute() 函數執行完後返回一個指向記錄集的指標,下面我們給出具體代碼並作說明:
_variant_t RecordsAffected;//執行SQL命令:CREATE TABLE建立表格users,users包含四個欄位:整形ID,字串username,整型age,日期型birthdaym_pConnection->Execute("CREATE TABLE users(ID INTEGER,usernameTEXT,old INTEGER,birthday DATETIME)",&RecordsAffected,adCmdText);//往表格裡面添加記錄m_pConnection->Execute("INSERT
INTO users(ID,username,old,birthday)VALUES (1, Washington,25,1970/1/1)",&RecordsAffected,adCmdText);//執行SQL統計命令得到包含記錄條數的記錄集m_pRecordset = m_pConnection->Execute("SELECT COUNT(*) FROMusers",&RecordsAffected,adCmdText);_variant_t vIndex = (long)0;_variant_t
vCount = m_pRecordset->GetCollect(vIndex);///取得第一個欄位的值放入vCount變數m_pRecordset->Close(); //關閉記錄集CString message;message.Format("共有%d條記錄",vCount.lVal);AfxMessageBox(message); //顯示目前記錄條數
(2) 利用Command對象來執行SQL命令
_CommandPtr m_pCommand;m_pCommand.CreateInstance("ADODB.Command");_variant_t vNULL;vNULL.vt = VT_ERROR;vNULL.scode = DISP_E_PARAMNOTFOUND; //定義為無參數m_pCommand->ActiveConnection = m_pConnection; //非常關鍵的一句,將建立的串連賦值給它m_pCommand->CommandText = "SELECT * FROM users"; //命令字串m_pRecordset = m_pCommand->Execute(&vNULL,&vNULL,adCmdText);//執行命令取得記錄集
在這段代碼中我們只是用Command對象來執行了SELECT查詢語句,Command對象在進行預存程序的調用中能真正體現它的作用。
(3) 直接用Recordset對象進行查詢取得記錄集,例如:
m_pRecordset->Open("SELECT * FROM users",_variant_t((IDispatch *)m_pConnection,true),adOpenStatic,adLockOptimistic,adCmdText);
Open()方法的原型如下:
HRESULT Recordset15::Open ( const _variant_t & Source, const _variant_t & ActiveConnection, enum CursorTypeEnum CursorType, enum LockTypeEnum LockType, long Options )
上述函數中參數Source是資料查詢字串;參數ActiveConnection是已經建立好的串連(我們需要用Connection對象指標來構造一個_variant_t對象);
參數CursorType游標類型,它可以是以下值之一:
enum CursorTypeEnum{ adOpenUnspecified = -1, //不作特別指定 adOpenForwardOnly = 0, //前滾靜態游標。這種游標只能向前瀏覽記錄集,比如用MoveNext向前滾動,這種方式可以提高瀏覽速度。但諸如BookMark, RecordCount,AbsolutePosition,AbsolutePage都不能使用 adOpenKeyset = 1, //採用這種游標的記錄集看不到其它使用者的新增、刪除操作,但對於更新原有記錄的操作對你是可見的。 adOpenDynamic
= 2, //動態游標。所有資料庫的操作都會立即在各使用者記錄集上反應出來。 adOpenStatic = 3 //靜態游標。它為你的記錄集產生一個靜態備份,但其它使用者的新增、刪除、更新操作對你的記錄集來說是不可見的。};
參數LockType表示資料庫的鎖定類型,它可以是以下值之一:
enum LockTypeEnum{ adLockUnspecified = -1, //未指定 adLockReadOnly = 1, //唯讀記錄集 adLockPessimistic = 2, //悲觀鎖定方式。資料在更新時鎖定其它所有動作,這是最安全的鎖定機制 adLockOptimistic = 3, //樂觀鎖定方式。只有在你調用Update方法時才鎖定記錄。在此之前仍然可以做資料的更新、插入、刪除等動作 adLockBatchOptimistic = 4, //樂觀分批更新。編輯時記錄不會鎖定,更改、插入及刪除是在批處理模式下完成。}
下面我們就按照上面的步驟採用RecordSet方式來編寫一個簡單的Demo:
1. 在Stdafx.h標頭檔中加入msado15.dll:
#import "c:\program files\common files\system\ado\msado15.dll" no_namespace rename ("EOF","adoEOF") rename("BOF", "adoBOF")
2. 初始化COM組件:
在*Dlg的初始化函數OnInitDialog()中,加入::CoInitialize(NULL)來初始化COM組件,同時,為了我們在後面更好地操作資料庫,我們也在該函數中添加連結資料庫的代碼:
pConn = new _ConnectionPtr(__uuidof(Connection)); //pConn is the type of _ConnectionPtr,and it's a member variable of *DlgpSet = new _RecordsetPtr(__uuidof(Recordset)); //pSet is the type of _RecordsetPtr, and it's a member variable of *Dlg try {CString connString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=odbcdemo.mdb;Mode=ReadWrite;Persist Security Info=False";pConn ->Open((_bstr_t)connString, "", "", adConnectUnspecified);pSet->Open("select * from studentinfo", _variant_t((IDispatch*)pConn), adOpenStatic, adLockOptimistic, adCmdText);}catch (_com_error &e){AfxMessageBox(e.Description());}
同時,為了讓其運行後就顯示資料,我們也可以將從資料庫中讀取的資料顯示到Edit控制項中。
即在try塊中調用ShowData()(註:該函數是我們自己添加的一個用於將資料顯示在Edit控制項中的自訂函數,目的:避免代碼重複)
3. 通過上面的步驟,運行程式後,介面上的Edit控制項中已經有顯示了從資料庫中讀取到的資料。接下來我們就來定位元據庫中的記錄。
至於定位元據庫中的記錄,無非就是第一條、前一條、後一條和最後一條:下面就是我們的實現代碼:
void CADODemoDlg::OnButtonFirst() {// TODO: Add your control notification handler code herepSet ->MoveFirst();ShowData();}void CADODemoDlg::OnButtonPrevious() {// TODO: Add your control notification handler code herepSet ->MovePrevious();if (pSet->adoBOF){pSet ->MoveFirst();}ShowData();}void CADODemoDlg::OnButtonNext() {// TODO: Add your control notification handler code herepSet->MoveNext();if (pSet ->adoEOF){pSet ->MoveLast();}ShowData();}void CADODemoDlg::OnButtonLast() {// TODO: Add your control notification handler code herepSet->MoveLast();ShowData();}/* The function is used to show data on windows form */void CADODemoDlg::ShowData(){m_edit_name = (LPCSTR)(_bstr_t)pSet->GetCollect("name");m_edit_id = (LPCSTR)(_bstr_t)pSet->GetCollect("id");m_edit_sex = (LPCSTR)(_bstr_t)pSet->GetCollect("sex");m_edit_age = (LPCSTR)(_bstr_t)pSet->GetCollect("age");m_edit_profession = (LPCSTR)(_bstr_t)pSet->GetCollect("profession");m_edit_address = (LPCSTR)(_bstr_t)pSet->GetCollect("address");UpdateData(FALSE);}
4. 完成資料庫記錄的定位,我們就該開始對資料庫中的記錄進行操作了,而對於資料庫的操縱,也就是增、刪、改、查。下面,哦我們就針對這四個方面,
來編寫我們的代碼:
void CADODemoDlg::OnButtonAdd() {// TODO: Add your control notification handler code herepSet->MoveLast();pSet->AddNew();UpdateData(TRUE);pSet->put_Collect(_variant_t("name"), _variant_t(m_edit_name));pSet->put_Collect(_variant_t("id"), _variant_t(m_edit_id));pSet->put_Collect(_variant_t("age"), _variant_t(m_edit_age));pSet->put_Collect(_variant_t("sex"), _variant_t(m_edit_sex));pSet->put_Collect(_variant_t("profession"), _variant_t(m_edit_profession));pSet->put_Collect(_variant_t("address"), _variant_t(m_edit_address));/* use the method can also insert record into database*/// pSet->Fields->GetItem("name")->Value = (_bstr_t)m_edit_name;// pSet->Fields->GetItem("id")->Value = (_bstr_t)m_edit_id;// pSet->Fields->GetItem("sex")->Value = (_bstr_t)m_edit_sex;// pSet->Fields->GetItem("age")->Value = (_bstr_t)m_edit_age;// pSet->Fields->GetItem("profession")->Value = (_bstr_t)m_edit_profession;// pSet->Fields->GetItem("address") ->Value = (_bstr_t)m_edit_address;pSet ->Update();}void CADODemoDlg::OnButtonDelete() {// TODO: Add your control notification handler code herepSet->Delete(adAffectCurrent);//delete current recordAfxMessageBox("刪除成功!");}void CADODemoDlg::OnButtonUpdate() {// TODO: Add your control notification handler code hereUpdateData(TRUE);pSet->put_Collect(_variant_t("name"), _variant_t(m_edit_name));pSet->put_Collect(_variant_t("id"), _variant_t(m_edit_id));pSet->put_Collect(_variant_t("age"), _variant_t(m_edit_age));pSet->put_Collect(_variant_t("sex"), _variant_t(m_edit_sex));pSet->put_Collect(_variant_t("profession"), _variant_t(m_edit_profession));pSet->put_Collect(_variant_t("address"), _variant_t(m_edit_address));pSet->Update();ShowData();}void CADODemoDlg::OnButtonFind() {// TODO: Add your control notification handler code hereUpdateData(TRUE);pSet->MoveFirst();for (int i = 0; i < (pSet->GetRecordCount()); i++){if (m_edit_name == (LPCSTR)(_bstr_t)pSet->GetCollect("name")){ShowData();break;}pSet->MoveNext();}}
至此,我們採用記錄集的方式,完成了一個簡單的ADODEmo,但是需要注意的是:我們在OnInitDlg()中進行了記憶體的動態分配,所以應該手動添加解構函式釋放其記憶體空間,以免造成記憶體泄露。