ADO学习(四)ADO扩展IADORecordBinding
?
當我們使用Visual?C++進行ADO編程時,一項頗為頭疼的工作就是對VARIANT字段類型的處理。通常做法是,先把VARIANT類型轉(zhuǎn)換為形式上較為類似的C++類型,然后再把轉(zhuǎn)換后的數(shù)據(jù)存放在一個類(class)或結(jié)構(gòu)(structure)中。即便如此,對VARIANT數(shù)據(jù)類型的處理在一定程度上也影響到了程序的性能。
ADO為我們提供了一個接口,該接口使我們可以把數(shù)據(jù)直接讀取到本地,從而繞開對于復(fù)雜的VARIANT數(shù)據(jù)類型的處理。同時,ADO還定義了一組預(yù)處理宏,用來簡化接口的使用。用好這一工具,將會使我們的編程工作將變得輕松和高效。
IADORecordBinding接口
VC++對ADO的擴展聯(lián)系或綁定了一個Recordset對象的各個字段到C/C++變量。當被綁定的Recordset的當前行改變時,其中所有被綁定的字段的值也同樣會被拷貝到相應(yīng)的C/C++變量中。如果需要,被拷貝的數(shù)據(jù)還會自動進行相應(yīng)的數(shù)據(jù)類型轉(zhuǎn)換。
IADORecordBinding接口的BindToRecordset方法將字段綁定到C/C++變量之上。AddNew方法則是增加一個新的行到被綁定的Recordset。Update方法利用C/C++變量的值填充Recordset中新的行或更新已存在的行。
IADORecordBinding接口由Recordset對象實現(xiàn),你不需要自己編碼進行實現(xiàn)。
綁定條目
VC++對ADO的擴展在一個Recordset對象與一個C/C++變量間進行映像(Map)。一個字段與對應(yīng)的一個變量間的映像被稱作一個綁定條目。預(yù)定義的宏為數(shù)字、定長或不定長數(shù)據(jù)提供了綁定條目。所有的綁定條目與相應(yīng)的C/C++變量都被封裝、聲明在一個從VC++擴展類CADORecordBinding派生的類中。這個CADORecordBinding類在內(nèi)部由綁定條目宏定義。
在ADO內(nèi)部,將所有宏的參數(shù)都映射在一個OLE?DB?DBBINDING結(jié)構(gòu)中,并創(chuàng)建一個OLE?DB訪問子(Accessor)對象來管理所有的行為和字段與變量間的數(shù)據(jù)轉(zhuǎn)換。OLE?DB定義的數(shù)據(jù)由以下三部分組成:存儲數(shù)據(jù)的緩沖區(qū);一個狀態(tài)值表示一個字段是否被成功地被存入緩沖區(qū),或變量值是否被成功地存入字段;數(shù)據(jù)長度。(參見OLE?DB程序員參考第6章:讀寫數(shù)據(jù)的更多信息)
所需的頭文件
為了使用VC++對ADO的擴展,你得在你的應(yīng)用中包含這個頭文件:#include?<icrsint.h>
綁定Recordset的字段
要綁定Recordset的字段到C/C++變量,需要這樣做:?
1.創(chuàng)建一個CADORecordsetBinding的派生類。
2.在派生類中定義綁定條目和相應(yīng)的C/C++變量。注意不要使用逗號、分號切斷宏。每個宏都會自動地定義適當?shù)姆指舴?/span>
為每個被映像的字段定義一個綁定條目。并注意根據(jù)不同情況選用ADO_FIXED_LENGTH_ENTRY、?ADO_NUMERIC_ENTRY、ADO_VARIABLE_LENGTH_ENTRY中的某個宏。
3.在你的應(yīng)用中,創(chuàng)建一個該派生類的實例。從Recordset中獲得IADORecordBinding接口,然后調(diào)用BindToRecordset方法將Recordset的所有字段綁定到對應(yīng)的C/C++變量之上。
請參見示例程序以獲得更多信息。
接口方法
IADORecordBinding接口只有三個方法:BindToRecordset,?AddNew,和Update。每個方法所需的唯一的參數(shù)就是一個CADORecordBinding派生類的實例指針。因此,AddNew和Update方法不能使用任何與它們同名的ADO方法中的參數(shù)。
語法
BindToRecordset方法將字段綁定到C/C++變量之上。
BindToRecordset(CADORecordBinding?*binding)
AddNew方法則引用了它的同名ADO函數(shù),來增加一個新的記錄行。
AddNew(CADORecordBinding?*binding)
Update方法也引用了它的同名ADO函數(shù),來更新Recordset。
Update(CADORecordBinding?*binding)
綁定條目宏
綁定條目宏定義了一個Recordset字段與一個變量間的對應(yīng)關(guān)系。每個條目的綁定宏由開始宏與結(jié)束宏組成并配對使用。
定長數(shù)據(jù)的宏適用于adDate,adBoolean等,數(shù)字的宏適用于adTinyInt,?adInteger和adDouble等,變長數(shù)據(jù)的宏適用于adChar,?adVarChar和adVarBinary等。所有的數(shù)字類型,除了adVarNumeric以外也是定長數(shù)據(jù)類型。每個宏的族之間都有不同的參數(shù)組,因此你可以排除不感興趣的綁定信息。
參見OLE?DB程序員參考附錄A:數(shù)據(jù)類型的更多信息
開始綁定條目
BEGIN_ADO_BINDING(Class)
定長數(shù)據(jù):
ADO_FIXED_LENGTH_ENTRY(Ordinal,?DataType,?Buffer,?Status,?Modify)
ADO_FIXED_LENGTH_ENTRY2(Ordinal,?DataType,?Buffer,?Modify)
數(shù)字型數(shù)據(jù):
ADO_NUMERIC_ENTRY(Ordinal,?DataType,?Buffer,?Precision,?Scale,?Status,?Modify)
ADO_NUMERIC_ENTRY2(Ordinal,?DataType,?Buffer,?Precision,?Scale,?Modify)
變長數(shù)據(jù):?
ADO_VARIABLE_LENGTH_ENTRY(Ordinal,?DataType,?Buffer,?Size,?Status,?Length,?Modify)
ADO_VARIABLE_LENGTH_ENTRY2(Ordinal,?DataType,?Buffer,?Size,?Status,?Modify)
ADO_VARIABLE_LENGTH_ENTRY3(Ordinal,?DataType,?Buffer,?Size,?Length,?Modify)
ADO_VARIABLE_LENGTH_ENTRY4(Ordinal,?DataType,?Buffer,?Size,?Modify)
結(jié)束綁定
END_ADO_BINDING()
?
| 參數(shù): | 描述 |
| Class: | 綁定單元和C/C++變量定義所在的類。 |
| Ordinal: | 序數(shù)類型,從1開始計數(shù)的Recordset字段序號,該字段對應(yīng)于指定的C/C++變量。 |
| DataType: | 和ADO中的數(shù)據(jù)類型等價的C/C++數(shù)據(jù)類型。相應(yīng)的Recordset字段在需要時將轉(zhuǎn)換為該數(shù)據(jù)類型。 |
| Buffer: | 用來存儲Recordset字段的緩沖區(qū)名稱。 |
| Size: | 緩沖區(qū)的最大尺寸。 |
| Status: | 狀態(tài)位。指示緩沖區(qū)的內(nèi)容的有效性,以及字段轉(zhuǎn)換是否成功。其中有兩個比較重要的值。一個是adFldOK,?表明轉(zhuǎn)換是成功的;另一個是adFldNull,?表明字段值為NULL。更多的狀態(tài)值,請參考MSDN |
| Modify: | 布爾類型。如果為TRUE,?表明ADO允許更新緩沖區(qū)中的數(shù)據(jù)。如果為FALSE,表明數(shù)據(jù)是只讀的。 |
| Precision: |
|
| Scale: | 數(shù)值類型的小數(shù)位數(shù)。Number?of?decimal?places?in?a?numeric?variable. |
| Length: |
|
狀態(tài)值
變量Status的值指示了一個字段的值是否被成功的拷貝到了對應(yīng)的變量中。寫數(shù)據(jù)時,可以給Status賦值為adFldNull來指示該字段將被設(shè)置為null。
常量?值?描述
adFldOK?0?一個非空的字段值被返回。
adFldBadAccessor?1?綁定無效。
adFldCantConvertValue?2?值因為符號不匹配或超界外的原因?qū)е聼o法被正確轉(zhuǎn)換。
adFldNull?3?讀字段值時,指示一個空值被返回。寫字段值時,指示當字段自身無法編碼NULL時該字段將被設(shè)置為NULL。
adFldTruncated?4?變長數(shù)據(jù)或數(shù)字被截斷。
adFldSignMismatch?5?值是有符號數(shù),而數(shù)據(jù)類型是無符號數(shù)。
adFldDataOverFlow?6?數(shù)據(jù)值超出界限。
adFldCantCreate?7?不知名的列類型和字段已經(jīng)被打開。
adFldUnavailable?8?字段值無法確定。比如一個新的未賦值的無缺省值的字段。
adFldPermissionDenied?9?未被允許更新數(shù)據(jù)。
adFldIntegrityViolation?10?更新字段時值違反了列的完整性要求。
adFldSchemaViolation?11?更新字段時值違反了列的規(guī)范要求。
adFldBadStatus?12?更新字段時,無效的狀態(tài)參數(shù)。
adFldDefault?13?更新字段時,使用缺省值。
使用VC++對ADO的擴展的示例
在這個例子中,還使用了COM專有的“智能指針”功能,它能自動處理IADORecordBinding接口的QueryInterface和引用計數(shù)。如果沒有智能指針,你得這樣編碼:
IADORecordBinding?*picRs?=?NULL;
...
TESTHR(pRs->QueryInterface(
__uuidof(IADORecordBinding),?(LPVOID*)&picRs));
...
if?(picRs)?picRs->Release();
使用智能指針,你可以用這樣的語句從IADORecordBinding接口派生IADORecordBindingPtr類型:
_COM_SMARTPTR_TYPEDEF(IADORecordBinding,?__uuidof(IADORecordBinding));
然后這樣實例化指針:
IADORecordBindingPtr?picRs(pRs);
因為VC++的擴展由Recordset對象實現(xiàn),因此智能指針picRs的構(gòu)造函數(shù)使用了_RecordsetPtr類指針pRs。構(gòu)造函數(shù)利用pRs調(diào)用QueryInterface來獲得IADORecordBinding接口。
//?以下即是示例程序
//?tt.cpp?:?定義控制臺應(yīng)用程序的入口點。
//
#include?"stdafx.h"
#import?"c:\Program?Files\Common?Files\System\ADO\msado15.dll"?no_namespace?rename("EOF",?"EndOfFile")
?
#include?<icrsint.h>
_COM_SMARTPTR_TYPEDEF(IADORecordBinding,?__uuidof(IADORecordBinding));
?
inline?void?TESTHR(HRESULT?_hr)?{?if?FAILED(_hr)?_com_issue_error(_hr);?}
?
class?CCustomRs?:?public?CADORecordBinding
{
BEGIN_ADO_BINDING(CCustomRs)
ADO_VARIABLE_LENGTH_ENTRY2(1,?adVarChar,?m_sz_SID,sizeof(m_sz_SID),?m_ul_SID,?false)
ADO_VARIABLE_LENGTH_ENTRY2(2,?adVarChar,?m_sz_SNAME,sizeof(m_sz_SNAME),?m_ul_SNAME,?false)
ADO_VARIABLE_LENGTH_ENTRY2(3,?adVarChar,?m_sz_TID,sizeof(m_sz_TID),?m_ul_TID,?false)
END_ADO_BINDING()
public:
?
CHAR????m_sz_SID[22];
CHAR????m_sz_SNAME[32];
CHAR????m_sz_TID[32];
?
ULONG???m_ul_SID;
ULONG???m_ul_SNAME;
ULONG???m_ul_TID;
};
?
int?_tmain(int?argc,?_TCHAR*?argv[])
{
::CoInitialize(NULL);
?
//智能指針
_ConnectionPtr?m_pConnection;
?
try?
{
//創(chuàng)建連接對象實例
m_pConnection.CreateInstance(__uuidof(Connection));
m_pConnection->Open("Provider=SQLOLEDB.1;Password=123456;Persist?Security?Info=True;User?ID=sa;Initial?Catalog=CAMPUS;Data?Source=192.168.0.102","","",adModeUnknown);
//數(shù)據(jù)集指針
_RecordsetPtr?pRst("ADODB.Recordset");
_variant_t?RecordsAffected;
pRst=m_pConnection->Execute((_bstr_t)("select?*?from?student"),?&RecordsAffected,?adCmdText);
?
//數(shù)據(jù)集綁定
CCustomRs?rs;
IADORecordBindingPtr?picRs(pRst);
?
TESTHR(picRs->BindToRecordset(&rs));
?
while?(!pRst->EndOfFile)
{
//?處理CCustomRs中的數(shù)據(jù)
printf("Sid=%s?Sname=%s?Tid=%s\n",rs.m_sz_SID,rs.m_sz_SNAME,rs.m_sz_TID);
?
//?移動到下一行,新行的值會被自動填充到對應(yīng)的CCustomRs的變量中
pRst->MoveNext();
}
}
catch?(_com_error?&e?)
{
printf("Error:\n");
printf("Code?=?%08lx\n",?e.Error());
printf("Meaning?=?%s\n",?e.ErrorMessage());
printf("Source?=?%s\n",?(LPCSTR)?e.Source());
printf("Description?=?%s\n",?(LPCSTR)?e.Description());
}
::CoUninitialize();
?
return?0;
}
?
?
?
?
?
?
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的ADO学习(四)ADO扩展IADORecordBinding的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ADO学习(九)如何阅读ADO文档
- 下一篇: 复制SQLSERVER数据库文件