当前位置:首页 > ado数据库编程
10、邦定数据
定义一个绑定类,将其成员变量绑定到一个指定的记录集,以方便于访问记录集的字段值。
(1). 从cadorecordbinding派生出一个类:
class ccustomrs : public cadorecordbinding {
begin_ado_binding(ccustomrs)
ado_variable_length_entry2(3, advarchar, m_szau_fname, sizeof(m_szau_fname), lau_fnamestatus, false)
ado_variable_length_entry2(2, advarchar, m_szau_lname, sizeof(m_szau_lname), lau_lnamestatus, false)
ado_variable_length_entry2(4, advarchar, m_szphone, sizeof(m_szphone), lphonestatus, true) end_ado_binding()
public:
char m_szau_fname[22]; ulong lau_fnamestatus; char m_szau_lname[42]; ulong lau_lnamestatus; char m_szphone[14]; ulong lphonestatus; };
其中将要绑定的字段和变量名用begin_ado_binding宏关联起来。每个字段对应于两个变量,一个存放字段的值,另一个存放字段的状态。字段用从1开始的序号表示,如1,2,3等等。
特别要注意的是:如果要绑定的字段是字符串类型,则对应的字符数组的元素个数一定要比字段长度大2(比如m_szau_fname[22],其绑定的字段au_fname的长度实际是20),不这样绑定就会失败。我分析多出的2可能是为了存放字符串结尾的空字符null和bstr字符串开头的一个字(表示bstr的长度)。这个问题对于初学者来说可能是个意想不到的问题。
cadorecordbinding类的定义在icrsint.h文件里,内容是:
class cadorecordbinding {
public:
stdmethod_(const ado_binding_entry*, getadobindingentries) (void) pure; };
begin_ado_binding宏的定义也在icrsint.h文件里,内容是:
#define begin_ado_binding(cls) public: \ typedef cls adorowclass; \
const ado_binding_entry* stdmethodcalltype getadobindingentries() { \ static const ado_binding_entry rgadobindingentries[] = {
ado_variable_length_entry2宏的定义也在icrsint.h文件里:
#define ado_variable_length_entry2(ordinal, datatype, buffer, size, status, modify)\ {ordinal, \ datatype, \ 0, \ 0, \ size, \
offsetof(adorowclass, buffer), \ offsetof(adorowclass, status), \ 0, \
classoffset(cadorecordbinding, adorowclass), \ modify},
#define end_ado_binding宏的定义也在icrsint.h文件里:
#define end_ado_binding() {0, adempty, 0, 0, 0, 0, 0, 0, 0, false}};\ return rgadobindingentries;} (2). 绑定
_recordsetptr rs1;
iadorecordbinding *picrs=null; ccustomrs rs; ......
rs1->queryinterface(__uuidof(iadorecordbinding), (lpvoid*)&picrs));
picrs->bindtorecordset(&rs);
派生出的类必须通过iadorecordbinding接口才能绑定,调用他的bindtorecordset方法就行了。
(3). rs中的变量即是当前记录字段的值
//set sort and filter condition: // step 4: manipulate the data
rs1->fields->getitem(\ rs1->sort = \
rs1->filter = \
rs1->movefirst();
while (variant_false == rs1->endoffile) {
printf(\\t %s\tphone: %s\n\
(rs.lau_fnamestatus == adfldok ? rs.m_szau_fname : \ (rs.lau_lnamestatus == adfldok ? rs.m_szau_lname : \(rs.lphonestatus == adfldok ? rs.m_szphone : \if (rs.lphonestatus == adfldok) strcpy(rs.m_szphone, \
testhr(picrs->update(&rs)); // add change to the batch rs1->movenext(); }
rs1->filter = (long) adfilternone; ......
if (picrs) picrs->release(); rs1->close(); pconn->close();
只要字段的状态是adfldok,就能访问。如果修改了字段,不要忘了先调用picrs的update(注意不是recordset的update),然后才关闭,也不要忘了释放picrs(即picrs->release();)。
(4). 此时还能用iadorecordbinding接口添加新纪录
if(failed(picrs->addnew(&rs))) ......
11. 访问长数据
在microsoft sql中的长数据包括text、image等这样长类型的数据,作为二进制字节来对待。
能用field对象的getchunk和appendchunk方法来访问。每次能读出或写入全部数据的一部分,他会记住上次访问的位置。不过如果中间访问了别的字段后,就又得从头来了。
请看下面的例子:
//写入一张照片到数据库: variant varchunk; safearray *psa;
safearraybound rgsabound[1];
//vt_array │ vt_ui1
cfile f(\\\aaa.jpg\byte bval[chunksize+1]; uint uisread=0;
//create a safe array to store the array of bytes while(1) {
uisread=f.read(bval,chunksize);
if(uisread==0)break;
rgsabound[0].celements =uisread; rgsabound[0].llbound = 0;
psa = safearraycreate(vt_ui1,1,rgsabound); for(long index=0;index if(failed(safearrayputelement(psa,&index,&bval[index]))) ::messagebox(null,\啊,又出毛病了。\提示\ } varchunk.vt = vt_array│vt_ui1; varchunk.parray = psa; try{ m_precordset->fields->getitem(\ } catch (_com_error &e) { cstring str=(char*)e.description(); ::messagebox(null,str+\\n又出毛病了。\提示\ } ::variantclear(&varchunk); ::safearraydestroydata( psa); if(uisread //从数据库读一张照片: cfile f; f.open(\\\bbb.jpg\ long lphotosize = m_precordset->fields->item[\ long lisread=0; _variant_t varchunk; byte buf[chunksize]; while(lphotosize>0) { lisread=lphotosize>=chunksize? chunksize:lphotosize; varchunk = m_precordset->fields-> item[\ for(long index=0;index ::safearraygetelement(varchunk.parray,&index,buf+index); } f.write(buf,lisread); lphotosize-=lisread;
共分享92篇相关文档