使用属性的get/put/putref
在vb中,属性的名称并未被检验,无论它是被读取、被赋值,或者赋予一个引用。
public sub getputputref
dim rs as new adodb.recordset
dim cn as new adodb.connection
dim sz as integer
cn.open "provider=sqloledb;data source=yourserver;" & _
"initial catalog=pubs;user id=sa;password=;"
rs.pagesize = 10
sz = rs.pagesize
rs.activeconnection = cn
rs.open "authors",,adopenstatic
' ...
rs.close
cn.close
end sub
以下是vc++关于get/put/putrefproperty的演示
1.这个例子演示了省略字符串参数的两种形式:一种是采用常量strmissing,另一种则是由编译器自动生成一个临时的存在于open方法使用期间的_bstr_t。
2.因为操作数已经是(idispatch *)的指针,所以没有必要将rs->putrefactiveconnection(cn)的操作数再进行类型转换。
#import "c:\program files\common files\system\ado\msado15.dll" \
no_namespace rename("eof", "endoffile")
#include <stdio.h>
void main(void)
{
coinitialize(null);
try
{
_connectionptr cn("adodb.connection");
_recordsetptr rs("adodb.recordset");
_bstr_t strmissing(l"");
long oldpgsz = 0,
newpgsz = 5;
// note 1
cn->open("provider=sqloledb;data source=a-tima10;"
"initial catalog=pubs;user id=sa;password=;",
strmissing, "",
adconnectunspecified);
oldpgsz = rs->getpagesize();
// -or-
oldpgsz = rs->pagesize;
rs->putpagesize(newpgsz);
// -or-
rs->pagesize = newpgsz;
// note 2
rs->putrefactiveconnection( cn );
rs->open("authors", vtmissing, adopenstatic, adlockreadonly,
adcmdtable);
printf("original pagesize = %d, new pagesize = %d\n", oldpgsz,
rs->getpagesize());
rs->close();
cn->close();
}
catch (_com_error &e)
{
printf("description = %s\n", (char*) e.description());
}
::couninitialize();
}
使用getitem(x)和item[x]
下面是vb中关于item()的标准与交互语法的演示。
public sub getitemitem
dim rs as new adodb.recordset
dim name as string
rs = rs.open "authors", "dsn=pubs;", adopendynamic, _
adlockbatchoptimistic, adtable
name = rs(0)
' -or-
name = rs.fields.item(0)
rs(0) = "test"
rs.updatebatch
' restore name
rs(0) = name
rs.updatebatch
rs.close
end sub
以下则是vc++关于item的演示
当访问collection中的item时,索引值2必须被转换为long类型以确保正确的构造函数被调用。
#import "c:\program files\common files\system\ado\msado15.dll" \
no_namespace rename("eof", "endoffile")
#include <stdio.h>
void main(void)
{
coinitialize(null);
try {
_recordsetptr rs("adodb.recordset");
_variant_t vtfirstname;
rs->open("authors",
"provider=sqloledb;data source=a-tima10;"
"initial catalog=pubs;user id=sa;password=;",
adopenstatic, adlockoptimistic, adcmdtable);
rs->movefirst();
// note 1.取得一个字段的名称
vtfirstname = rs->fields->getitem((long)2)->getvalue();
// -or-
vtfirstname = rs->fields->item[(long)2]->value;
printf( "first name = '%s'\n", (char*) ((_bstr_t) vtfirstname));
rs->fields->getitem((long)2)->value = l"test";
rs->update(vtmissing, vtmissing);
// 恢复原名称
rs->fields->getitem((long)2)->putvalue(vtfirstname);
// -or-
rs->fields->getitem((long)2)->value = vtfirstname;
rs->update(vtmissing, vtmissing);
rs->close();
}
catch (_com_error &e)
{
printf("description = '%s'\n", (char*) e.description());
}
::couninitialize();
}
利用(idispatch *)转换ado对象的指针类型
1.在一个variant中显式地封装一个活动的connection对象,然后用(idispatch *)进行类型转换确保正确的构造函数被调用。同时明确地设置第二个参数为缺省的true,使该对象的引用计数在recordset:pen操作完成后仍得到正确的维护。
2.表达式(_bstr_t)不是一个类型转换,而是一个_variant_t的操作符,用以从中提取一个_bstr_t字符串。
表达式(char*)也不是一个类型转换,而是一个_bstr_t的操作符,用以从中提取封装在_bstr_t中的字符串的指针。
下面这些代码演示了_variant_t和_bstr_t的一些常见操作。
#import "c:\program files\common files\system\ado\msado15.dll" \
no_namespace rename("eof", "endoffile")
#include <stdio.h>
void main(void)
{
coinitialize(null);
try
{
_connectionptr pconn("adodb.connection");
_recordsetptr prst("adodb.recordset");
pconn->open("provider=sqloledb;data source=a-tima10;"
"initial catalog=pubs;user id=sa;password=;",
"", "", adconnectunspecified);
// note 1
prst->open(
"authors",
_variant_t((idispatch *) pconn, true),
adopenstatic,
adlockreadonly,
adcmdtable);
prst->movelast();
// note 2
printf("last name is '%s %s'\n",
(char*) ((_bstr_t) prst->getfields()->getitem("au_fname")->getvalue()),
(char*) ((_bstr_t) prst->fields->item["au_lname"]->value));
prst->close();
pconn->close();
}
catch (_com_error &e)
{
printf("description = '%s'\n", (char*) e.description());
}
::couninitialize();
}
///////////////////////////////////////////////
vc++对ado的扩展
///////////////////////////////////////////////
对于vc++程序员而言,每次都要将ado返回的数据转换成一般的c++数据类型,接着将数据存入一个类或结构总是一件枯燥的事。更讨厌的是这也带来了效率的低下。
因此,ado提供了一个接口以支持将数据直接返回为一个本地化的c/c++数据类型而非variant,并提供了一系列的预处理宏来方便使用这些接口。这样做的结果是一个复杂的工具可以很轻松的被使用并能获得很好的性能。
一个普通的c/c++客户场景是将一个recordset中的一条记录绑定到一个包含本地c/c++数据类型的c/c++结构或类之上。如果通过variant传递数据,这意味着要编写大量的转换代码,以在variant和c/c++本地类型间进行数据转换。vc++对ado的扩展出现的目的就是要简化这一过程。
如何使用vc++对ado的扩展
iadorecordbinding接口
vc++对ado的扩展联系或绑定了一个recordset对象的各个字段到c/c++变量。当被绑定的recordset的当前行改变时,其中所有被绑定的字段的值也同样会被拷贝到相应的c/c++变量中。如果需要,被拷贝的数据还会自动进行相应的数据类型转换。
iadorecordbinding接口的bindtorecordset方法将字段绑定到c/c++变量之上。addnew方法则是增加一个新的行到被绑定的recordset。update方法利用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_entry、ado_variable_length_entry中的某个宏。
3.在你的应用中,创建一个该派生类的实例。从recordset中获得iadorecordbinding接口,然后调用bindtorecordset方法将recordset的所有字段绑定到对应的c/c++变量之上。
请参见示例程序以获得更多信息。
接口方法
iadorecordbinding接口只有三个方法:bindtorecordset, addnew,和update。每个方法所需的唯一的参数就是一个cadorecordbinding派生类的实例指针。因此,addnew和update方法不能使用任何与它们同名的ado方法中的参数。
语法
bindtorecordset方法将字段绑定到c/c++变量之上。
bindtorecordset(cadorecordbinding *binding)
addnew方法则引用了它的同名ado函数,来增加一个新的记录行。
addnew(cadorecordbinding *binding)
update方法也引用了它的同名ado函数,来更新recordset。
update(cadorecordbinding *binding)
绑定条目宏
绑定条目宏定义了一个recordset字段与一个变量间的对应关系。每个条目的绑定宏由开始宏与结束宏组成并配对使用。
定长数据的宏适用于addate,adboolean等,数字的宏适用于adtinyint, adinteger和addouble等,变长数据的宏适用于adchar, advarchar和advarbinary等。所有的数字类型,除了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 派生类的名字。
ordinal 从1开始的序号,对应于recordset中的字段。
datatype 与c/c++变量对应的ado数据类型(参见datatypeenum以获得有效数据类型的列表)。如果需要,字段的值会被转换成该类型的值。
buffer 对应的c/c++变量的名字。
size 该c/c++变量的最大字节数。如果是个变长字符串,使用0表示即可。
status 指示变量的名字。该变量用以表示缓冲是否有效,数据转换是否成功。值adfldok意味着转换成功;adfldnull意味着该字段的值为空。其他可能的值见后面的状态值列表。
modify 逻辑标志。true意味着ado允许利用变量值更新recordset中的字段的值。设置该值为true将允许更新,如果你只想检查字段的值而不想改变它那么就设置为false。
precision 数字型变量的位数。
scale 数字型变量的小数位数。
length 一个4字节变量的名字。该变量将包含缓冲区中数据的实际长度。
状态值
变量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接口。
// 以下即是示例程序
#import "c:\program files\common files\system\ado\msado15.dll" \
no_namespace rename("eof", "endoffile")
#include <stdio.h>
#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(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)
end_ado_binding()
public:
char m_ch_fname[22];
char m_ch_lname[32];
ulong m_ul_fnamestatus;
ulong m_ul_lnamestatus;
};
void main(void)
{
::coinitialize(null);
try
{
_recordsetptr prs("adodb.recordset");
ccustomrs rs;
iadorecordbindingptr picrs(prs);
prs->open("select * from employee order by lname",
"dsn=pubs;uid=sa;pwd=;",
adopenstatic, adlockoptimistic, adcmdtext);
testhr(picrs->bindtorecordset(&rs));
while (!prs->endoffile)
{
// 处理ccustomrs中的数据
printf("name = %s %s\n",
(rs.m_ul_fnamestatus == adfldok ? rs.m_ch_fname: "<error>"),
(rs.m_ul_lnamestatus == adfldok ? rs.m_ch_lname: "<error>"));
// 移动到下一行,新行的值会被自动填充到对应的ccustomrs的变量中
prs->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();
} |