ADO学习(四)ADO扩展IADORecordBinding

 

当我们使用Visual C++进行ADO编程时,一项颇为头疼的工作就是对VARIANT字段类型的处理。通常做法是,先把VARIANT类型转换为形式上较为类似的C++类型,然后再把转换后的数据存放在一个类(class)或结构(structure)中。即便如此,对VARIANT数据类型的处理在一定程度上也影响到了程序的性能。

  ADO为我们提供了一个接口,该接口使我们可以把数据直接读取到本地,从而绕开对于复杂的VARIANT数据类型的处理。同时,ADO还定义了一组预处理宏,用来简化接口的使用。用好这一工具,将会使我们的编程工作将变得轻松和高效。

IADORecordBinding接口
VC++ADO的扩展联系或绑定了一个Recordset对象的各个字段到C/C++变量。当被绑定的Recordset的当前行改变时,其中所有被绑定的字段的值也同样会被拷贝到相应的C/C++变量中。如果需要,被拷贝的数据还会自动进行相应的数据类型转换。
IADORecordBinding接口的BindToRecordset方法将字段绑定到C/C++变量之上。AddNew方法则是增加一个新的行到被绑定的RecordsetUpdate方法利用C/C++变量的值填充Recordset中新的行或更新已存在的行。
IADORecordBinding接口由Recordset对象实现,你不需要自己编码进行实现。

绑定条目
VC++ADO的扩展在一个Recordset对象与一个C/C++变量间进行映像(Map)。一个字段与对应的一个变量间的映像被称作一个绑定条目。预定义的宏为数字、定长或不定长数据提供了绑定条目。所有的绑定条目与相应的C/C++变量都被封装、声明在一个从VC++扩展类CADORecordBinding派生的类中。这个CADORecordBinding类在内部由绑定条目宏定义。
ADO内部,将所有宏的参数都映射在一个OLE DB DBBINDING结构中,并创建一个OLE DB访问子(Accessor)对象来管理所有的行为和字段与变量间的数据转换。OLE DB定义的数据由以下三部分组成:存储数据的缓冲区;一个状态值表示一个字段是否被成功地被存入缓冲区,或变量值是否被成功地存入字段;数据长度。(参见OLE DB程序员参考第6章:读写数据的更多信息)

所需的头文件
为了使用VC++ADO的扩展,你得在你的应用中包含这个头文件:#include <icrsint.h>

绑定Recordset的字段
要绑定Recordset的字段到C/C++变量,需要这样做: 
1.创建一个CADORecordsetBinding的派生类。
2.在派生类中定义绑定条目和相应的C/C++变量。注意不要使用逗号、分号切断宏。每个宏都会自动地定义适当的分隔符。
为每个被映像的字段定义一个绑定条目。并注意根据不同情况选用ADO_FIXED_LENGTH_ENTRY、 ADO_NUMERIC_ENTRYADO_VARIABLE_LENGTH_ENTRY中的某个宏。
3.在你的应用中,创建一个该派生类的实例。从Recordset中获得IADORecordBinding接口,然后调用BindToRecordset方法将Recordset的所有字段绑定到对应的C/C++变量之上。
请参见示例程序以获得更多信息。

接口方法
IADORecordBinding接口只有三个方法:BindToRecordset, AddNew,Update。每个方法所需的唯一的参数就是一个CADORecordBinding派生类的实例指针。因此,AddNewUpdate方法不能使用任何与它们同名的ADO方法中的参数。

语法
BindToRecordset方法将字段绑定到C/C++变量之上。
BindToRecordset(CADORecordBinding *binding)
AddNew方法则引用了它的同名ADO函数,来增加一个新的记录行。
AddNew(CADORecordBinding *binding)
Update方法也引用了它的同名ADO函数,来更新Recordset
Update(CADORecordBinding *binding)

绑定条目宏
绑定条目宏定义了一个Recordset字段与一个变量间的对应关系。每个条目的绑定宏由开始宏与结束宏组成并配对使用。
定长数据的宏适用于adDateadBoolean等,数字的宏适用于adTinyInt, adIntegeradDouble等,变长数据的宏适用于adChar, adVarCharadVarBinary等。所有的数字类型,除了adVarNumeric以外也是定长数据类型。每个宏的族之间都有不同的参数组,因此你可以排除不感兴趣的绑定信息。
参见OLE DB程序员参考附录A:数据类型的更多信息

开始绑定条目
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


一个四字节的变量。用来包含缓冲区中数据的实际长度。


状态值
变量Status的值指示了一个字段的值是否被成功的拷贝到了对应的变量中。写数据时,可以给Status赋值为adFldNull来指示该字段将被设置为null
常量 值 描述
adFldOK 0 一个非空的字段值被返回。
adFldBadAccessor 1 绑定无效。
adFldCantConvertValue 2 值因为符号不匹配或超界外的原因导致无法被正确转换。
adFldNull 3 读字段值时,指示一个空值被返回。写字段值时,指示当字段自身无法编码NULL时该字段将被设置为NULL
adFldTruncated 4 变长数据或数字被截断。
adFldSignMismatch 5 值是有符号数,而数据类型是无符号数。
adFldDataOverFlow 6 数据值超出界限。
adFldCantCreate 7 不知名的列类型和字段已经被打开。
adFldUnavailable 8 字段值无法确定。比如一个新的未赋值的无缺省值的字段。
adFldPermissionDenied 9 未被允许更新数据。
adFldIntegrityViolation 10 更新字段时值违反了列的完整性要求。
adFldSchemaViolation 11 更新字段时值违反了列的规范要求。
adFldBadStatus 12 更新字段时,无效的状态参数。
adFldDefault 13 更新字段时,使用缺省值。

使用VC++ADO的扩展的示例
在这个例子中,还使用了COM专有的智能指针功能,它能自动处理IADORecordBinding接口的QueryInterface和引用计数。如果没有智能指针,你得这样编码:
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对象实现,因此智能指针picRs的构造函数使用了_RecordsetPtr类指针pRs。构造函数利用pRs调用QueryInterface来获得IADORecordBinding接口。

// 以下即是示例程序
// tt.cpp : 定义控制台应用程序的入口点。

//

#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, adVarCharm_sz_SID,sizeof(m_sz_SID), m_ul_SIDfalse)

ADO_VARIABLE_LENGTH_ENTRY2(2, adVarCharm_sz_SNAME,sizeof(m_sz_SNAME), m_ul_SNAMEfalse)

ADO_VARIABLE_LENGTH_ENTRY2(3, adVarCharm_sz_TID,sizeof(m_sz_TID), m_ul_TIDfalse)

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_TCHARargv[])

{

::CoInitialize(NULL);

 

//智能指针

_ConnectionPtr m_pConnection;

 

try 

{

//创建连接对象实例

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);

//数据集指针

_RecordsetPtr pRst("ADODB.Recordset");

_variant_t RecordsAffected;

pRst=m_pConnection->Execute((_bstr_t)("select * from student"), &RecordsAffectedadCmdText);

 

//数据集绑定

CCustomRs rs;

IADORecordBindingPtr picRs(pRst);

 

TESTHR(picRs->BindToRecordset(&rs));

 

while (!pRst->EndOfFile)

{

// 处理CCustomRs中的数据

printf("Sid=%s Sname=%s Tid=%s\n",rs.m_sz_SID,rs.m_sz_SNAME,rs.m_sz_TID);

 

// 移动到下一行,新行的值会被自动填充到对应的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", (LPCSTRe.Source());

printf("Description = %s\n", (LPCSTRe.Description());

}

::CoUninitialize();

 

return 0;

}

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值