1. 程式人生 > >VC++ ADO操作總結

VC++ ADO操作總結

1、匯入庫檔案

#import "C:\Program Files\commonfiles\system\ado\msado15.dll" no_namespace rename("EOF","EndOfFile")rename("BOF","FirstOfFile")
使用ADO前必須在工程的stdafx.h檔案最後用直接引入符號#import引入ADO庫檔案,以使編譯器能正確編譯。程式碼如下:

ADO類的定義是作為一種資源儲存在ADO DLL(msado15.dll)中,在其內部稱為型別庫。

型別庫描述了自治介面,以及C++使用的COM vtable介面。

當使用#import指令時,在執行時Visual C++需要從ADO DLL中讀取這個型別庫,

並以此建立一組C++標頭檔案。這些標頭檔案具有.tli 和.tlh副檔名,#import引入ADO庫檔案的程式碼編譯後,在專案的目錄下生成了這兩個檔案。在C++程式程式碼中呼叫的ADO類要在這些檔案中定義。

no_namespace指示ADO物件不使用名稱空間,在有些應用程式中,

由於應用程式中的物件與ADO中的物件之間可能會出現命名衝突,所以有必要使用名稱空間。

如果要使用名稱空間,則可把第三行程式修改為: rename_namespace("AdoNS")。

rename("EOF","EndOfFile")表示將ADO中的EOF(檔案結束)更名為adoEOF,因為檔案的結尾也是以EOF結尾的,是為了避免與定義了自己的EOF的其他庫衝突。 至於改為什麼名字,可以根據自己的命名習慣自己確定。

2、初始化COM環境

OLE DB 是基於COM技術編寫的,ADO是OLE DB基礎之上的使用者程式,

OLE DB是一個COM元件,在訪問COM元件的時候需要初始化COM庫,方法如下:

(1)  ::CoInitialize(NULL); //初始化OLE/COM庫環境

釋放程式碼:

::CoUninitialize();//既然初始化了環境,當然一定要記得釋放他了

(2)也可以呼叫MFC全域性函式

AfxOleInit();

3、三大指標物件的定義和建立例項

(1)

_ConnectionPtrpConnection("ADODB.Connection");

_RecordsetPtrpRecordset("ADODB.Recordset");

_CommandPtrpCommand("ADODN.Command");

(2)

_ConnectionPtr pConnection;

_RecordsetPtr pRecordset;

_CommandPtr pCommand;

 

pConnection.CreateInstance(__uuidof(Connection));

pRecordset.CreateInstance(__uuidof(Recordset));

pCommand.CreateInstance(__uuidof(Command));

要產生一個智慧指標物件,其實在定義的同時也可以初始化,如:

_ConnectionPtrpConnection(__uuidof(Connection));

_ConnectionPtr 是智慧指標

__uuidof() 用來獲取Connection全域性唯一識別符號

(3)

_ConnectionPtr pConnection;

_RecordsetPtr pRecordset;

_CommandPtr pCommand;

 

pConnection.CreateInstance("ADODB.Connection");

pRecordset.CreateInstance("ADODB.Recordset");

pCommand.CreateInstance("ADODB.Command"); 

4、開啟一個連線

pConnection->ConnectionString = "這裡的字串有下面四種寫法";//對連線字串賦值

pConnection->Open(ConnectionString,"","",adModeUnknown);//連線資料庫
//第二三個引數分別為使用者的ID與密碼,

因為在連線字串ConnectionCstring中已經設定好了,這裡可以為空。

第四個引數可以取下面兩個引數:

adAsyncConnect

非同步開啟資料庫,在ASP中直接用16

adConnectUnspecified

同步開啟資料庫,在ASP中直接用-1

ConnectionString根據不同的資料來源,分別對應不同的寫法

(要記下來很困難,可以在VB中利用ADO控制元件先連線好,再將其拷貝在VC中,這樣不容易出錯)

    1)

訪問Access 2000

"Provider=Microsoft.Jet.OLEDB.4.0;DataSource=databaseName;UserID=userName;Password=userPassWord"

   2)

訪問ODBC資料

"Provider=MADASQL;DSN=dsnName;UID=userName;PWD=userPassword;"

   3)

訪問Oracle資料庫

“Provider=MSDAORA;DataSourse=serverName;User ID=userName;Password=userPassword;"

   4)

訪問MS SQL資料庫

"Provider=SQLOLEDB,DataSource=serverName;Initial Catalog=databaseName;UserID=userName;Password=userPassword;"

5、執行SQL命令,得到資料

方法1:

pRecordset =pConnection->Execute("Select * from authors",NULL,adCmdText);

方法2:

pRecordset ->Open("Select * fromauthors",_

variant_t((Idispacth*) pConnection), //設定活動連線

adOpenDynamtic,

//遊標型別

adLockOptimistic,

//鎖的型別

adCmdText);

方法3:

pCommand->put_ActiveConnection(_variant_t((Idispatch*) pConn);

pCommand->CommandText = "Select *from authors";

pRecordset =pCmd->Execute(NULL,NULL,adCmdText);

得到資料之後,做一個迴圈取得資料:

While (!pRecordset ->adoEOF)

{

Str =pRecordset->GetCollect("au_lname"));

pRst->MoveNext();

}

SQL命令比較多,但是不去考慮細節,這裡只說出通用的方法

CString strSQL;//定義SQL命令串,用來儲存SQL語句
strSQL.Format("SQL statement");

然後在每個要用到SQL命令串的方法中,使用strSQL.AllocSysString()的方法進行型別轉換

6、com的專用資料型別

variant ,bstr ,SafeArray

variant變數的範圍包括很多,它是一種變體型別,主要用於支援自動化的語言訪問,

從而在VB中非常方便地使用,但是VC中比較複雜,它使用_variant_t 進行管理

bstr是一種字串變數,使用_bstr_t進行管理,這個類過載了char *操作符

7、關閉連線

if(pConnection->State);     //不能多次關閉,否則會出現錯誤

{

pConnection->Close();   //先判斷狀態,然後再關閉,其它類似

}

pRecordset->Close();

pCommand.Release();

pConnection.Release();

//釋放引用計數

pRecordset.Release();

 注意:呼叫Close()時用"->",呼叫Release()時要用".",為什麼?

因為智慧指標,_ConnectionPtr是一個過載了->運算子的類

_ConnectionPtr:它是一個介面指標模板。'.'是模板_com_ptr的函式。->是'介面函式'呼叫。

//forexample:

_ConnectionPtr m_Conn;

m_Conn.CreateInstance(....);//Createinterfaceinstance.

m_Conn->Open(...);//Openaconnectiontodatabase.

'->'是_com_ptr過載了的運算子.目的就是為了讓你呼叫模板引數的函式.

8、結構化異常處理

ADO封裝了COM介面,所以需要進行錯誤處理

如下例:

HRESULT hr;
try{

hr =m_pConnection.CreateInstance("ADODB.Connection");///建立Connection物件

if(SUCCEEDED(hr))

{

hr =m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;DataSource=test.mdb","","",adModeUnknown);///連線資料庫

///上面一句中連線字串中的Provider是針對ACCESS2000環境的,對於ACCESS97,需要改為:Provider=Microsoft.Jet.OLEDB.3.51;

}

}catch(_com_error e)///捕捉異常

{

CString errormessage;

errormessage.Format("連線資料庫失敗!\r\n錯誤資訊:%s",e.ErrorMessage());

AfxMessageBox(errormessage);///顯示錯誤資訊
}

ACCESS中使用日期比較

關於access中資料型別不匹配的問題between #1993-04-26# and #1993-05-26#

2006-10-11 16:06

/問題:
//基於Access
//VC中使用sql語句查詢某一日期範圍內的資料
//查詢語句如下:
m_pSet->Open(CRecordset::snapshot,_T("select * from data01 where date between '1993-04-26' and '1993-05-26'"),CRecordset::executeDirect);
//執行出現的報錯總是:標準表示式中資料型別不匹配!
 
//VC+Access這個已經是老問題了:)
//不過,同學問的這個問題,我還是頭次遇到
//昨天反覆查詢原因花去我2個多小時:(
//最後還是在百度裡搜到瞭解答

//網路裡的高手總是很多^_^
 
//最後可行的解決方案如下:
//由於資料庫用的是Access,所以日期要用#1993-04-26#而不是"1993-04-26"
m_pSet->Open(CRecordset::snapshot,_T("select * from data01 where date between #1993-04-26# and #1993-05-26#"),CRecordset::executeDirect);

獲取執行SQL函式後的返回值 EGSUM(RoundInfo.RoundLen) from RoundInfo,Main where Main.Date between 2009-1-2 and 2012-2-3"

temp_Str=L“SUM(RoundInfo.RoundLen) from RoundInfo,Main where Main.Date between 2009-1-2 and 2012-2-3"

HRESULT hr = m_ptrRecordset->Open(_bstr_t(temp_Str), _variant_t((IDispatch*)m_ptrConnection, TRUE),

                   adOpenStatic, adLockBatchOptimistic, adCmdUnknown);

if(!m_ptrRecordset->adoEOF)  //必需首先判斷資料集是否是空,否則如果直接GetCollect()的話,會報出錯誤

{             

_variant_t    varNo = (_variant_t)m_ptrRecordset->GetCollect ((long)0);

if(varNo.vt!=VT_NULL)   //判斷是否是空記錄

{

AvgLen = (long)varNo;

}

}
 

函式總結:

m_ptrRecordset->get_RecordCount(&this->m_threeRoundEnough);

獲取查詢結果的數量(即個數)

_variant_t    varNo = (_variant_t)m_ptrRecordset->GetCollect ((long)0);

這句話的意思是獲取第一列當前行的值,如果是查詢之後直接用這句話,則指取第一行第一列的值,取下一列,則加上

m_ptrRecordset->MoveNext();

hr = m_ptrRecordset->Open(_bstr_t(temp_Str), _variant_t((IDispatch*)m_ptrConnection, TRUE), adOpenStatic, adLockBatchOptimistic, adCmdUnknown);// temp_Str是查詢命令

              ASSERT(m_ptrRecordset);

              if(hr != S_OK)

              {

                   m_ptrConnection->Close();

                   AfxMessageBox(L"create recordset error!");

                   return false;

              }

              if(!m_ptrRecordset->adoEOF)

              {

              _variant_t    varNo = (_variant_t)m_ptrRecordset->GetCollect ((long)0);  //得到查詢結果的值

              if(varNo.vt!=VT_NULL)

              {

              MinCount = varNo;

              }

              }