2008-09-14 19:30:22
標簽:數據庫 VC MFC ADO [推送到技術(shù)圈]
| 版權聲明:原創(chuàng )作品,允許轉載,轉載時(shí)請務(wù)必以超鏈接形式標明文章 原始出處 、作者信息和本聲明。否則將追究法律責任。http://orajc.blog.51cto.com/458434/99310 |
| 為了在VC中使用Ado,需要在頭文件中加入以下幾行代碼: #import "C:\\program files\\common files\\system\\ado\\msado15.dll" no_namespace rename("EOF", "adoEOF") #include "adoid.h" #include "icrsint.h" 第一行的#import語(yǔ)句告訴編譯器把此指令中的DLL文件引入到程序中,并從庫中抽取其中的對象的類(lèi)信息,并產(chǎn)生兩個(gè)頭文件包含在工程中.其中的no_namespace 用來(lái)對DLL的名稱(chēng)域進(jìn)行隔離,最后的rename,把ADO中的EOF重新命名,避免和其他地方的定義的EOF產(chǎn)生沖突. 第三行引入的頭文件定義啦ADO2.0的類(lèi)和接口標識 第四行引入了ADO2.0的數據綁定擴展. 例子代碼如下: //數據庫連接例子 AfxOleInit();//初始化 _ConnectionPtr m_pConnection; //_ConnectionPtr對象用來(lái)實(shí)現和數據源的連接 HRESULT hr = CoInitialize(NULL); m_pConnection.CreateInstance(__uuidof(Connection)); //_bstr_t ConnectionString = "DSN=Test;UID=sa;PWD=;";//DSN---Access //_bstr_t ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Test.mdb";//NON_DSN---Access _bstr_t ConnectionString = "Provider=MSDASQL;DRIVER={SQL SERVER};SERVER=BILLGATES;DATABASE=NORTHWIND;UID=;PWD=;";//NON_DSN---SQL SERVER _bstr_t userName = ""; _bstr_t password = ""; _RecordsetPtr pRecordSet; _bstr_t bstrQuery("SELECT * FROM data"); _variant_t vNull; vNull.vt = VT_ERROR; vNull.scode = DISP_E_PARAMNOTFOUND; try { m_pConnection->Open(ConnectionString,"","",adModeUnknown); hr = pRecordSet.CreateInstance(__uuidof(Recordset)); if(SUCCEEDED(hr)) { pRecordSet->PutRefActiveConnection(m_pConnection); hr = pRecordSet->Open(_variant_t(bstrQuery),vNull,adOpenForwardOnly,adLockOptimistic,adCmdText); AfxMessageBox("連接數據庫成功!"); if(!pRecordSet->adoEOF) { _variant_t name = pRecordSet->GetCollect("name");//獲得指定列的數據 CString strName = (char*)_bstr_t(name);//轉換數據類(lèi)型 AfxMessageBox(strName); COleSafeArray vaFieldlist;//數據表字段名 vaFieldlist.CreateOneDim(VT_VARIANT,3); long lArrayIndex[1]; lArrayIndex[0] = 0; vaFieldlist.PutElement(lArrayIndex, &(_variant_t("name"))); lArrayIndex[0] = 1; vaFieldlist.PutElement(lArrayIndex, &(_variant_t("age"))); lArrayIndex[0] = 2; vaFieldlist.PutElement(lArrayIndex, &(_variant_t("address"))); COleSafeArray vaValuelist;//數據部字段值 vaValuelist.CreateOneDim(VT_VARIANT,3); lArrayIndex[0] = 0; vaValuelist.PutElement(lArrayIndex, &(_variant_t("liuy"))); lArrayIndex[0] = 1; vaValuelist.PutElement(lArrayIndex, &(_variant_t("23"))); lArrayIndex[0] = 2; vaValuelist.PutElement(lArrayIndex, &(_variant_t("beijing"))); for(int i = 0; i< 2; i++) { pRecordSet->AddNew(vaFieldlist,vaValuelist);//添加一行記錄 } AfxMessageBox("添加數據成功"); } } } catch(_com_error &e) { _bstr_t bstrSource(e.Source()); _bstr_t bstrDescription(e.Description()); TRACE("Exception thrown for classes generated by #import"); TRACE("\tCode=%O81x\n",e.Error); TRACE("\tCode meaning = %s\n",e.ErrorMessage); TRACE("\tSource = %s\n",(LPCTSTR)bstrSource); TRACE("\tDescription = %s\n",(LPCTSTR)bstrDescription); AfxMessageBox(e.ErrorMessage()); } _ConnectionPtr 的Open()數的意義: ConnectionString:包含連接信息的字符串 UID:訪(fǎng)問(wèn)數據庫的用戶(hù)名 PSWD:訪(fǎng)問(wèn)數據庫的口令 Option:可選參數 _RecordsetPtr的Open()函數: HRESULT Open(const _variant_t& source, const _variant_t& conneciton, enum CursorTypeEnum curdorType, enum LockTypeEnum lockType, long options) Source 參數是一個(gè)變體類(lèi)型,她可以是一個(gè)Command的對象,一SQL對象,一個(gè)表名或一個(gè)存儲過(guò)程,甚至是一個(gè)URL, 一個(gè)文件名,一個(gè)流對象. Conneciton也是一個(gè)變體類(lèi)型,他可以是一個(gè)connection對象,也可以是一個(gè)指明連接目標的字符串. cursorType指明了數據集游標的類(lèi)型.她可以是以下幾個(gè)值:adOpenDynamic,adOpenForwardOnly,adOpenKeyset,adOpenStatic,adOpenUnspecified. lockType參數可以是下列值之一:adLockBachOptiomistic,adlockOptimistic,adLockPessimistic,adLockReadOnly,adLockUnspecified. Options:參數指明了第一個(gè)參數source的類(lèi)型,其值可以是adCmdUnspecified,adCmdText, adCmdTable,adCmdStoreProc,adCmdUnknow,adCmdFile,adCmdTableDirect |
//====
首先,要用#import語(yǔ)句來(lái)引用支持ADO的組件類(lèi)型庫(*.tlb),其中類(lèi)型庫可以作為可執行程序(DLL、EXE等)的一部分被定位在其自身程序中的附屬資源里,如:被定位在msado15.dll的附屬資源中,只需要直接用#import引用它既可??梢灾苯釉?/span>Stdafx.h文件中加入下面語(yǔ)句來(lái)實(shí)現:
#import "c:\program files\common files\system\ado\msado15.dll" no_namespace rename ("EOF", "adoEOF")
其中路徑名可以根據自己系統安裝的ADO支持文件的路徑來(lái)自行設定。當編譯器遇到#import語(yǔ)句時(shí),它會(huì )為引用組件類(lèi)型庫中的接口生成包裝類(lèi),#import語(yǔ)句實(shí)際上相當于執行了API涵數LoadTypeLib()。#import語(yǔ)句會(huì )在工程可執行程序輸出目錄中產(chǎn)生兩個(gè)文件,分別為*.tlh(類(lèi)型庫頭文件)及*.tli(類(lèi)型庫實(shí)現文件),它們分別為每一個(gè)接口產(chǎn)生智能指針,并為各種接口方法、枚舉類(lèi)型,CLSID等進(jìn)行聲明,創(chuàng )建一系列包裝方法。語(yǔ)句no_namespace說(shuō)明ADO對象不使用命名空間,rename ("EOF", "adoEOF")說(shuō)明將ADO中結束標志EOF改為adoEOF,以避免和其它庫中命名相沖突。
其次,在程序初始過(guò)程中需要初始化組件,一般可以用CoInitialize(NULL);來(lái)實(shí)現,這種方法在結束時(shí)要關(guān)閉初始化的COM,可以用下面語(yǔ)句CoUnInitialize();來(lái)實(shí)現。在MFC中還可以采用另一種方法來(lái)實(shí)現初始化COM,這種方法只需要一條語(yǔ)句便可以自動(dòng)為我們實(shí)現初始化COM和結束時(shí)關(guān)閉COM的操作,語(yǔ)句如下所示: AfxOleInit();
接著(zhù),就可以直接使用ADO的操作了。我們經(jīng)常使用的只是前面用#import語(yǔ)句引用類(lèi)型庫時(shí),生成的包裝類(lèi).tlh中聲明的智能指針中的三個(gè),它們分別是_ConnectionPtr、_RecordsetPtr和_CommandPtr。下面分別對它們的使用方法進(jìn)行介紹:
1、_ConnectionPtr智能指針,通常用于打開(kāi)、關(guān)閉一個(gè)庫連接或用它的Execute方法來(lái)執行一個(gè)不返回結果的命令語(yǔ)句(用法和_CommandPtr中的Execute方法類(lèi)似)。
——打開(kāi)一個(gè)庫連接。先創(chuàng )建一個(gè)實(shí)例指針,再用Open打開(kāi)一個(gè)庫連接,它將返回一個(gè)IUnknown的自動(dòng)化接口指針。代碼如下所示: _ConnectionPtr m_pConnection;
// 初始化COM,創(chuàng )建ADO連接等操作
AfxOleInit();
m_pConnection.CreateInstance(__uuidof(Connection));
// 在ADO操作中建議語(yǔ)句中要常用try...catch()來(lái)捕獲錯誤信息,
// 因為它有時(shí)會(huì )經(jīng)常出現一些意想不到的錯誤。jingzhou xu
try
{
// 打開(kāi)本地Access庫Demo.mdb
m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Demo.mdb","","",adModeUnknown);
}
catch(_com_error e)
{
AfxMessageBox("數據庫連接失敗,確認數據庫Demo.mdb是否在當前路徑下!");
return FALSE;
}
——關(guān)閉一個(gè)庫連接。如果連接狀態(tài)有效,則用Close方法關(guān)閉它并賦于它空值。代碼如下所示: if(m_pConnection->State)
m_pConnection->Close();
m_pConnection= NULL;
2、_RecordsetPtr智能指針,可以用來(lái)打開(kāi)庫內數據表,并可以對表內的記錄、字段等進(jìn)行各種操作。
——打開(kāi)數據表。打開(kāi)庫內表名為DemoTable的數據表,代碼如下: _RecordsetPtr m_pRecordset;
m_pRecordset.CreateInstance(__uuidof(Recordset));
// 在ADO操作中建議語(yǔ)句中要常用try...catch()來(lái)捕獲錯誤信息,
// 因為它有時(shí)會(huì )經(jīng)常出現一些意想不到的錯誤。jingzhou xu
try
{
m_pRecordset->Open("SELECT * FROM DemoTable", // 查詢(xún)DemoTable表中所有字段
theApp.m_pConnection.GetInterfacePtr(), // 獲取庫接庫的IDispatch指針
adOpenDynamic,
adLockOptimistic,
adCmdText);
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
——讀取表內數據。將表內數據全部讀出并顯示在列表框內,m_AccessList為列表框的成員變量名。如果沒(méi)有遇到表結束標志adoEOF,則用GetCollect(字段名)或m_pRecordset->Fields->GetItem(字段名)->Value方法,來(lái)獲取當前記錄指針所指的字段值,然后再用MoveNext()方法移動(dòng)到下一條記錄位置。代碼如下所示: _variant_t var;
CString strName,strAge;
try
{
if(!m_pRecordset->BOF)
m_pRecordset->MoveFirst();
else
{
AfxMessageBox("表內數據為空");
return;
}
// 讀入庫中各字段并加入列表框中
while(!m_pRecordset->adoEOF)
{
var = m_pRecordset->GetCollect("Name");
if(var.vt != VT_NULL)
strName = (LPCSTR)_bstr_t(var);
var = m_pRecordset->GetCollect("Age");
if(var.vt != VT_NULL)
strAge = (LPCSTR)_bstr_t(var);
m_AccessList.AddString( strName + " --> "+strAge );
m_pRecordset->MoveNext();
}
// 默認列表指向第一項,同時(shí)移動(dòng)記錄指針并顯示
m_AccessList.SetCurSel(0);
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
——插入記錄??梢韵扔?/span>AddNew()方法新增一個(gè)空記錄,再用PutCollect(字段名,值)輸入每個(gè)字段的值,最后再Update()更新到庫中數據既可。其中變量m_Name和m_Age分別為姓名及年齡編輯框的成員變量名。代碼所下所示: try
{
// 寫(xiě)入各字段值
m_pRecordset->AddNew();
m_pRecordset->PutCollect("Name", _variant_t(m_Name));
m_pRecordset->PutCollect("Age", atol(m_Age));
m_pRecordset->Update();
AfxMessageBox("插入成功!");
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
——移動(dòng)記錄指針。移動(dòng)記錄指針可以通過(guò)MoveFirst()方法移動(dòng)到第一條記錄、MoveLast()方法移動(dòng)到最后一條記錄、MovePrevious()方法移動(dòng)到當前記錄的前一條記錄、MoveNext()方法移動(dòng)到當前記錄的下一條記錄。但我們有時(shí)經(jīng)常需要隨意移動(dòng)記錄指針到任意記錄位置時(shí),可以使用Move(記錄號)方法來(lái)實(shí)現,注意: Move()方法是相對于當前記錄來(lái)移動(dòng)指針位置的,正值向后移動(dòng)、負值向前移動(dòng),如:Move(3),當前記錄是3時(shí),它將從記錄3開(kāi)始往后再移動(dòng)3條記錄位置。代碼如下所示: try
{
int curSel = m_AccessList.GetCurSel();
// 先將指針移向第一條記錄,然后就可以相對第一條記錄來(lái)隨意移動(dòng)記錄指針
m_pRecordset->MoveFirst();
m_pRecordset->Move(long(curSel));
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
——修改記錄中字段值??梢詫⒂涗浿羔樢苿?dòng)到要修改記錄的位置處,直接用PutCollect(字段名,值)將新值寫(xiě)入并Update()更新數據庫既可??梢杂蒙厦娣椒ㄒ苿?dòng)記錄指針,修改字段值代碼如下所示: try
{
// 假設對第二條記錄進(jìn)行修改
m_pRecordset->MoveFirst();
m_pRecordset->Move(1); // 從0開(kāi)始
m_pRecordset->PutCollect("Name", _variant_t(m_Name));
m_pRecordset->PutCollect("Age", atol(m_Age));
m_pRecordset->Update();
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
——刪除記錄。刪除記錄和上面修改記錄的操作類(lèi)似,先將記錄指針移動(dòng)到要修改記錄的位置,直接用Delete()方法刪除它并用Update()來(lái)更新數據庫既可。代碼如下所示: try
{
// 假設刪除第二條記錄
m_pRecordset->MoveFirst();
m_pRecordset->Move(1); // 從0開(kāi)始
m_pRecordset->Delete(adAffectCurrent); // 參數adAffectCurrent為刪除當前記錄
m_pRecordset->Update();
}
catch(_com_error *e)
{
AfxMessageBox(e->ErrorMessage());
}
——關(guān)閉記錄集。直接用Close方法關(guān)閉記錄集并賦于其空值。代碼如下所示: m_pRecordset->Close();
m_pRecordset = NULL;
3、CommandPtr智能指針,可以使用_ConnectionPtr或_RecordsetPtr來(lái)執行任務(wù),定義輸出參數,執行存儲過(guò)程或SQL語(yǔ)句。
——執行SQL語(yǔ)句。先創(chuàng )建一個(gè)_CommandPtr實(shí)例指針,再將庫連接和SQL語(yǔ)句做為參數,執行Execute()方法既可。代碼如下所示: _CommandPtr m_pCommand;
m_pCommand.CreateInstance(__uuidof(Command));
m_pCommand->ActiveConnection = m_pConnection; // 將庫連接賦于它
m_pCommand->CommandText = "SELECT * FROM DemoTable"; // SQL語(yǔ)句
m_pRecordset = m_pCommand->Execute(NULL, NULL,adCmdText); // 執行SQL語(yǔ)句,返回記錄集
——執行存儲過(guò)程。執行存儲過(guò)程的操作和上面執行SQL語(yǔ)句類(lèi)似,不同點(diǎn)僅是CommandText參數中不再是SQL語(yǔ)句,而是存儲過(guò)程的名字,如Demo。另一個(gè)不同點(diǎn)就是在Execute()中參數由adCmdText(執行SQL語(yǔ)句),改為adCmdStoredProc來(lái)執行存儲過(guò)程。如果存儲過(guò)程中存在輸入、輸出參數的話(huà),需要使用到另一個(gè)智能指針_ParameterPtr來(lái)逐次設置要輸入、輸出的參數信息,并將其賦于_CommandPtr中Parameters參數來(lái)傳遞信息,有興趣的讀者可以自行查找相關(guān)書(shū)籍或MSDN。執行存儲過(guò)程的代碼如下所示: _CommandPtr m_pCommand;
m_pCommand.CreateInstance(__uuidof(Command));
m_pCommand->ActiveConnection = m_pConnection; // 將庫連接賦于它
m_pCommand->CommandText = "Demo";
m_pCommand->Execute(NULL,NULL, adCmdStoredProc);
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
ActiveX數據對象(ADO)是OLE DB上面的高層數據庫API。我們在C++程序中也可以調用ADO。本文將在VC 6.0環(huán)境下做一個(gè)小小的例子解釋如何使用ADO。
1. 生成應用程序框架并初始化OLE/COM庫環(huán)境
創(chuàng )建一個(gè)標準的MFC AppWizard(exe)應用程序,然后在應用程序類(lèi)的InitInstance函數中初始化OLE/COM庫(因為ADO庫是一個(gè)COM DLL庫)。
BOOL CADOTestApp::InitInstance()
{ //初始化OLE/COM庫環(huán)境
AfxOleInit();}
2. 引入ADO庫文件
使用ADO前必須在工程的stdafx.h文件里用直接引入符號#import引入ADO庫文件,以使編譯器能正確編譯。代碼如下:
#include 〈comdef.h〉
#import "c:\program files\common files\system\ado\msado15.dll"
no_namespace
rename ("EOF","adoEOF")
頭文件comdef.h使我們的應用程序能夠使用Visual C++中的一些特殊COM支持類(lèi),這些類(lèi)使得處理OLE自治更為容易一些,OLE自治是ADO使用的數據類(lèi)型。后三行使用#import指令在我們的應用程序中輸入ADO類(lèi)庫定義。
ADO類(lèi)的定義是作為一種資源存儲在ADO DLL(msado15.dll)中,在其內部稱(chēng)為類(lèi)型庫。類(lèi)型庫描述了自治接口,以及C++使用的COM vtable接口。當使用#import指令時(shí),在運行時(shí)Visual C++需要從ADO DLL中讀取這個(gè)類(lèi)型庫,并以此創(chuàng )建一組C++頭文件。這些頭文件具有.tli 和.tlh擴展名,讀者可以在項目的目錄下找到這兩個(gè)文件。在C++程序代碼中調用的ADO類(lèi)要在這些文件中定義。
程序的第三行指示ADO對象不使用名稱(chēng)空間。在有些應用程序中,由于應用程序中的對象與ADO中的對象之間可能會(huì )出現命名沖突,所以有必要使用名稱(chēng)空間。如果要使用名稱(chēng)空間,則可把第三行程序修改為: rename_namespace("AdoNS")。第四行代碼將ADO中的EOF(文件結束)更名為adoEOF,以避免與定義了自己的EOF的其他庫沖突。
3.利用智能指針進(jìn)行數據庫操作
在CaboutDlg頭文件中定義兩個(gè)ADO智能指針類(lèi)實(shí)例,并在對話(huà)框中加入一個(gè)ListCtrl。
_ConnectionPtr m_pConnection;
_RecordsetPtr m_pRecordset;
ClistCtrl m_List;
ADO庫包含三個(gè)智能指針:_ConnectionPtr、_CommandPtr和_RecordsetPtr。
_ConnectionPtr通常被用來(lái)創(chuàng )建一個(gè)數據連接或執行一條不返回任何結果的SQL語(yǔ)句,如一個(gè)存儲過(guò)程。
_CommandPtr返回一個(gè)記錄集。它提供了一種簡(jiǎn)單的方法來(lái)執行返回記錄集的存儲過(guò)程和SQL語(yǔ)句。在使用_CommandPtr接口時(shí),可以利用全局_ConnectionPtr接口,也可以在_CommandPtr接口里直接使用連接串。
_RecordsetPtr是一個(gè)記錄集對象。與以上兩種對象相比,它對記錄集提供了更多的控制功能,如記錄鎖定、游標控制等。
在OnInitDialog()中加入以下代碼:
BOOL CAboutDlg::OnInitDialog()
{
CDialog::OnInitDialog();
_variant_t TheValue;
m_List.ResetContent();
m_pConnection.CreateInstance(_uuidof(Connection));
m_pRecordset.CreateInstance(_uuidof(Recordset));
try{
m_pConnection->Open("DSN=ADOTest","","",0); //連接叫作ADOTest的ODBC數據源
m_pRecordset->Open("SELECT * FROM BlockDefine",(IDispatch*)m_pConnection,
adOpenDynamic,
adLockOptimistic,
adCmdText);
//執行SQL語(yǔ)句得到一個(gè)記錄集
while(!m_pRecordset->adoEOF)
//遍歷所有記錄
{
TheValue = m_pRecordset->GetCollect("BlockIndex");
//得到字段BlockIndex的值
if(TheValue.vt!=VT_NULL)
m_List.AddString((char*)_bstr_t(TheValue)); //將該值加入到列表控件中
m_pRecordset->MoveNext();
}
m_pRecordset->Close();
m_pConnection->Close();
}
catch(_com_error e) //異常處理
{
AfxMessageBox(e->ErrorMessage());
}
m_pRecordset = NULL;
m_pConnection = NULL;
return TRUE; // return TRUE unless you set the focus to a control
}
程序中通過(guò)_variant_t和_bstr_t轉換COM對象和C++類(lèi)型的數據, _variant_t類(lèi)封裝了OLE自治VARIANT數據類(lèi)型。在C++中使用_variant_t類(lèi)要比直接使用VARIANT數據類(lèi)型容易得多。
好,編譯后該程序就能運行了,但記住運行前要創(chuàng )建一個(gè)叫ADOTest的ODBC數據源。該程序將把表BlockDefine中的Bloc
kIndex字段值顯示在列表控件中。
聯(lián)系客服