Visual C++ ADO数据库编程入门(2)

用命令对象的方法来创建一个参数对象,其中的长度参数(第三个)如果是固定长度的类型,就填-1,如果是字符串等可变长度的就填其实际长度。Parameters是命令对象的一个容器,它的Append方法就是把创建的参数对象追加到该容器里。Append进去的参数按先后顺序与SQL语句中的问号从左至右一一对应。   (3). 执行命令打开记录集
// Open Recordset Object Rs1 = Cmd1->Execute( &vtEmpty, &vtEmpty2, adCmdText );
  但要注意,用Command和Connection对象的Execute方法得到的Recordset是只读的。因为在打开Recordset之前,我们无法设置它的LockType属性(其默认值为只读)。而在打开之后设置LockType不起作用。   我发现用上述方法得到记录集Rs1后,不但Rs1中的记录无法修改,即使直接用SQL语句修改同一表中任何记录都不行。   要想能修改数据,还是要用Recordset自己的Open方法才行,如:
try{ m_pRecordset->Open((IDispatch *) Cmd1, vtMissing, adOpenStatic, adLockOptimistic, adCmdUnspecified); } catch (_com_error &e) { ::MessageBox(NULL,"mytable表不存在。","提示",MB_OK │ MB_ICONWARNING); }
  Recordset对象的Open方法真是太好了,其第一个参数可以是SQL语句、表名字、命令对象指针等等。   9、响应ADO的通知事件   通知事件就是当某个特定事件发生时,由Provider通知客户程序,换句话说,就是由Provider调用客户程序中的一个特定的方法(即事件的处理函数)。所以为了响应一个事件,最关键的就是要实现事件的处理函数。   (1). 从ConnectionEventsVt接口派生出一个类   为了响应_Connection的通知事件,应该从ConnectionEventsVt接口派生出一个类:
class CConnEvent : public ConnectionEventsVt { private: ULONG m_cRef; public: CConnEvent() { m_cRef = 0; }; ~CConnEvent() {}; STDMETHODIMP QueryInterface(REFIID riid, void ** ppv); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); STDMETHODIMP raw_InfoMessage( struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection); STDMETHODIMP raw_BeginTransComplete( LONG TransactionLevel, struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection); ...... };
   (2). 实现每一个事件的处理函数(凡是带raw_前缀的方法都把它实现了):
STDMETHODIMP CConnEvent::raw_InfoMessage( struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection) { *adStatus = adStatusUnwantedEvent; return S_OK; };
  有些方法虽然你并不需要,但也必须实现它,只需简单地返回一个S_OK即可。但如果要避免经常被调用,还应在其中将adStatus参数设置为adStatusUnwantedEvent,则在本次调用后,以后就不会被调用了。 另外还必须实现QueryInterface, AddRef, 和Release三个方法:
STDMETHODIMP CConnEvent::QueryInterface(REFIID riid, void ** ppv) { *ppv = NULL; if (riid == __uuidof(IUnknown) ││ riid == __uuidof(ConnectionEventsVt)) *ppv = this; if (*ppv == NULL) return ResultFromScode(E_NOINTERFACE); AddRef(); return NOERROR; } STDMETHODIMP_(ULONG) CConnEvent::AddRef() { return ++m_cRef; }; STDMETHODIMP_(ULONG) CConnEvent::Release() { if (0 != --m_cRef) return m_cRef; delete this; return 0; }
  (3). 开始响应通知事件
// Start using the Connection events IConnectionPointContainer *pCPC = NULL; IConnectionPoint *pCP = NULL; hr = pConn.CreateInstance(__uuidof(Connection)); if (FAILED(hr)) return; hr = pConn->QueryInterface(__uuidof(IConnectionPointContainer), (void **)&pCPC); if (FAILED(hr)) return; hr = pCPC->FindConnectionPoint(__uuidof(ConnectionEvents), &pCP); pCPC->Release(); if (FAILED(hr)) return; pConnEvent = new CConnEvent(); hr = pConnEvent->QueryInterface(__uuidof(IUnknown), (void **) &pUnk); if (FAILED(hr)) return rc; hr = pCP->Advise(pUnk, &dwConnEvt); pCP->Release(); if (FAILED(hr)) return; pConn->Open("dsn=Pubs;", "sa", "", adConnectUnspecified);
  也就是说在连接(Open)之前就做这些事。   (4). 停止响应通知事件
pConn->Close(); // Stop using the Connection events hr = pConn->QueryInterface(__uuidof(IConnectionPointContainer), (void **) &pCPC); if (FAILED(hr)) return; hr = pCPC->FindConnectionPoint(__uuidof(ConnectionEvents), &pCP); pCPC->Release(); if (FAILED(hr)) return rc; hr = pCP->Unadvise( dwConnEvt ); pCP->Release(); if (FAILED(hr)) return;
  在连接关闭之后做这件事。 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);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值