程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> vc教程 >> 理解 Visual C++ Extensions for ADO

理解 Visual C++ Extensions for ADO

日期:2017/1/13 10:26:10      編輯:vc教程

  【前言】

  當我們使用Visual C++進行ADO編程時,一項頗為頭疼的工作就是對VARIANT字段類型的處理。通常做法是,先把VARIANT類型轉換為形式上較為類似的C++類型,然後再把轉換後的數據存放在一個類(class)或結構(structure)中。即便如此,對VARIANT數據類型的處理在一定程度上也影響到了程序的性能。

  ADO為我們提供了一個接口,該接口使我們可以把數據直接讀取到本地,從而繞開對於復雜的VARIANT數據類型的處理。同時,ADO還定義了一組預處理宏,用來簡化接口的使用。用好這一工具,將會使我們的編程工作將變得輕松和高效。

  一般情況下,我們從ADO獲得Recordset數據集,然後定義一個C/C++結構類型,再把Recordset中的記錄綁定到結構成員變量中。當遇到VARIANT類型時,情況變得復雜,你必須解決如何把VARIANT數據類型(數據庫)轉換到C/C++數據類型(本地)的問題。Visual C++ Extensions for ADO(為敘述方便,以下簡稱ADOExt)的目標就是使這一切變得簡單。

  【IADORecordBinding 接口簡介】

  ADOExt 把RecordSet記錄集中的字段綁定到C/C++變量中。一旦該Recordset當前行的數據發生改變,數據將被立即拷貝到綁定的C/C++變量中。根據需要,數據將被轉換到指定的C/C++數據類型。

  IADORecordBinding 接口的 BindToRecordset 成員方法用來實現數據庫字段到本地C/C++變量之間的綁定。如果要為Recordset新增一條記錄,可以使用AddNew方法。Update方法則用來把綁定的C/C++變量數據更新和升級到數據庫中。

  IADORecordBinding 接口的實現不用我們操心,Recordset對象悄悄的在幕後完成這一切。

  【綁定單元(Binding EntrIEs)簡介】

  ADOExt 把Recordset對象的字段類型映射到本地的C/C++變量中,我們把這種從一個數據庫字段映射到一個C/C++變量之間的過程定義稱為一個綁定單元(Binding EntrIEs)。綁定由宏來完成,可以綁定的類型包括數值型、定長、以及可變長度的數據。綁定的基本流程是:定義派生自CADORecordBinding(CADORecordBinding 類本身其實也是一組宏定義)的類,在類中使用特定的宏來實現數據綁定。然後,在類中聲明相應的C/C++變量。

  ADO 在內部把宏定義中的參數映射到一個OLE DB DBBINDING類型的結構中,並且創建一個OLE DB 存取對象用來管理字段和變量之間的數據移動和格式轉換。OLE DB 的數據定義包括三個部分:一個用來儲存數據的緩沖區;一個用來標示數據存取狀態,以及變量如何提取的狀態位;以及數據的長度。

  【頭文件包含】

  要使用 Visual C++ 的ADOExt, 你需要在應用程序中包含下列頭文件:

  #include

  【綁定Recordset 字段的過程】

  ■創建一個派生自CADORecordsetBinding的類。

  ■在派生類中設定綁定單元並定義相應的C/C++變量。這些綁定單元被界定在 BEGIN_ADO_BINDING 和 END_ADO_BINDING 之間。不要想當然的在宏定義間放置逗號或者分號,這些工作會由宏在內部自動實現。

  ■為每一個要映射為C/C++變量的數據庫字段指定一個綁定單元。根據需要從ADO_FIXED_LENGTH_ENTRY, ADO_NUMERIC_ENTRY, 或者 ADO_VARIABLE_LENGTH_ENTRY 這三個宏定義中選擇一個,並填寫上正確的參數。

  ■在你的引用程序中,創建一個該類的實例。從 Recordset 中獲取 IADORecordBinding 接口。然後調用BindToRecordset方法實現數據綁定。

  【接口方法定義】

  IADORecordBinding 接口有三個方法:BindToRecordset, AddNew, 以及 Update。這些方法有且只有一個指針類型的參數,該參數指向一個派生自CADORecordBinding的類實例。事實上,AddNew 和 Updage 方法 將分別調用 ADO 中的同名方法。

  語法:

  BindToRecordset 方法實現 Recordset 字段到 C/C++ 變量之間的綁定。

  BindToRecordset(CADORecordBinding *binding)

  AddNew 方法調用它的同名方法,ADO 中的 AddNew 方法,向 Recordset 中增加一條新的記錄。

  AddNew(CADORecordBinding *binding)

  Update 方法調用它在ADO中的同名方法 Update, 完成對Recordset的數據更新。

  Update(CADORecordBinding *binding)

  【理解綁定單元中的宏】

  綁定單元定義了Recordset字段和變量之間的聯系。 宏BEGIN_ADO_BINDING(Class)(開始宏)和END_ADO_BINDING()(結束宏)界定了一組綁定單元。

  綁定單元中的宏提供了對於下列字段類型的支持:

  ■定長類型的數據。例如 adDate 或 adBoolean

  ■數值型數據。例如 adTinyInt, adInteger, 以及 adDouble

  ■變長類型的數據。例如 adChar, adVarChar 以及 adVarBinary

  所有的數值型數據,除了 adVarNumeric 類型之外,同時也都是定長類型的數據。

  不同的宏定義使用不同類型的參數,這樣你就可以排除不感興趣的綁定信息。

  ■開始數據綁定

  BEGIN_ADO_BINDING(Class)

  ■定長類型的數據

ADO_FIXED_LENGTH_ENTRY(Ordinal, DataType, Buffer, Status, Modify)
ADO_FIXED_LENGTH_ENTRY2(Ordinal, DataType, Buffer, Modify)

  ■數值型數據

ADO_NUMERIC_ENTRY(Ordinal, DataType, Buffer, Precision, Scale, Status, Modify)
ADO_NUMERIC_ENTRY2(Ordinal, DataType, Buffer, Precision, Scale, Modify) 

  ■可變長度類型的數據

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)

  ■結束數據綁定

END_ADO_BINDING()


參數: 描述
Class: 綁定單元和C/C++變量定義所在的類。
Ordinal: 序數類型,從1開始計數的Recordset字段序號,該字段對應於指定的C/C++變量。
DataType:  和ADO中的數據類型等價的C/C++數據類型。相應的Recordset字段在需要時將轉換為該數據類型。
Buffer: 用來存儲Recordset字段的緩沖區名稱。
Size: 緩沖區的最大尺寸。 
Status: 狀態位。指示緩沖區的內容的有效性,以及字段轉換是否成功。其中有兩個比較重要的值。一個是adFldOK, 表明轉換是成功的;另一個是adFldNull, 表明字段值為NULL。更多的狀態值,請參考MSDN
Modify: 布爾類型。如果為TRUE, 表明ADO允許更新緩沖區中的數據。如果為FALSE,表明數據是只讀的。
Precision:
數值類型的精度。
Scale: 數值類型的小數位數。Number of decimal places in a numeric variable. 
Length:
一個四字節的變量。用來包含緩沖區中數據的實際長度。

  【Visual C++ Extensions 例程】

//引入msado15.dll文件,從而聲明了ADO類型庫
#import "c:Program FilesCommon FilesSystemADOmsado15.dll" no_namespace rename("EOF", "EndOfFile")

#include
#include file://在此處包含icrsint.h頭文件

file://_COM_SMARTPTR_TYPEDEF 宏定義了一個_com_ptr_t類型的智能(smart)指針IADORecordBingingPtr
_COM_SMARTPTR_TYPEDEF(IADORecordBinding, __uuidof(IADORecordBinding));

file://定義一個測試函數
inline void TESTHR(HRESULT _hr) { if FAILED(_hr) _com_issue_error(_hr); }

file://定義一個派生自CADORecordBinding的類
class CCustomRs : public CADORecordBinding
{
file://開始進行數據類型綁定
BEGIN_ADO_BINDING(CCustomRs)
file://把Recordset的第2個adVarChar類型的字段綁定到C/C++變量m_ch_fname上
ADO_VARIABLE_LENGTH_ENTRY2(2, adVarChar, m_ch_fname,
sizeof(m_ch_fname), m_ul_fnameStatus, false)
ADO_VARIABLE_LENGTH_ENTRY2(4, adVarChar, m_ch_lname,
sizeof(m_ch_lname), m_ul_lnameStatus, false)
file://結束綁定
END_ADO_BINDING()

file://緊接著定義上述宏中用到的C/C++變量
public:
CHAR m_ch_fname[22];
CHAR m_ch_lname[32];
ULONG m_ul_fnameStatus;
ULONG m_ul_lnameStatus;
};

file://開始程序執行
void main(void)
{
::CoInitialize(NULL); file://初始化COM對象
try
{
file://typedef _com_ptr_t<_Recordset, __uuidof(_Recordset)> _RecordsetPtr:指向一個_Recordset的智能指針
_RecordsetPtr pRs("ADODB.Recordset");

file://定義一個CCustomRS: public CADORecordBinding類的實例
CCustomRs rs;

file://把IADORecordBindingPtr接口類型對象picRs指定到pRs對象,從而實現接口和對象之間的關聯
IADORecordBindingPtr picRs(pRs);

file://調用_Recordset的Open方法取得Recordset對象
pRs->Open("SELECT * FROM Employee ORDER BY lname",
"dsn=pubs;uid=sa;pwd=;",
adOpenStatic, adLockOptimistic, adCmdText);

file://利用CCustomRS類中的宏定義,實現數據之間的綁定
file://如果綁定成功,我們就可以使用rs對象的屬性了
TESTHR(picRs->BindToRecordset(&rs));

file://大家注意,這裡的EndOfFile對應上文import語句中的rename("EOF", "EndOfFile"),其實就是EOF。rename的作用為了防止命名沖突。
while (!pRs->EndOfFile)
{
// Process data in the CCustomRs C++ instance variables.
printf("Name = %s %s ",
(rs.m_ul_fnameStatus == adFldOK ? rs.m_ch_fname: ""),
(rs.m_ul_lnameStatus == adFldOK ? rs.m_ch_lname: ""));

// Move to the next row of the Recordset.
// FIElds in the new row will automatically be
// placed in the CCustomRs C++ instance variables.

pRs->MoveNext();
}
}
catch (_com_error &e )
{
printf("Error: ");
printf("Code = %08lx ", e.Error());
printf("Meaning = %s ", e.ErrorMessage());
printf("Source = %s ", (LPCSTR) e.Source());
printf("Description = %s ", (LPCSTR) e.Description());
}

file://清除COM對象實例
::CoUninitialize();
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved