数学建模社区-数学中国

标题: [转帖]在Visual C++中用ADO进行数据库编程(上) [打印本页]

作者: god    时间: 2005-3-30 22:50
标题: [转帖]在Visual C++中用ADO进行数据库编程(上)
1. 生成应用程序框架并初始化OLE/COM库环境 " p0 S: F9 D/ n0 ^* j" e' V4 e

& R/ k* a; ?. f6 C. @# C  创建一个标准的MFC AppWizard(exe)应用程序,然后在使用ADO数据库的InitInstance函数中初始化OLE/COM库(因为ADO库是一个COM DLL库)。$ }/ f4 u' H2 ?+ A" K3 g
本例为:
/ N% T- x0 E7 M, n* `( f9 l" ~6 e. K8 T, [
 BOOL CAdotestDlg::OnInitDialog()) W* M; D! ]! u
 {
$ @& c* C- k3 Y       ::CoInitialize(NULL); //初始化OLE/COM库环境
4 B( n* V+ B6 M) v }
* X6 K5 z4 j2 I' E$ z, y$ H. b9 A6 S) b5 j; h, w+ X$ ]2 Y$ a
  程序最后要调用 ::CoUninitialize();//释放程序占用的COM 资源。1 s5 O5 w  w, p) j9 P
, F% Y. @, `- E' m+ W+ ]
  另外:% G# {/ A, |  M, q4 \; e0 [0 t
7 C/ l2 c8 m# @0 m7 x
m_pRecordset->Close(); 注意!!!不要多次关闭!!!!!!!!!!!!
7 t. f" `; Y8 {9 `/ o  ?m_pConnection->Close();
0 S' F) ]* _* N$ @: jm_pRecordset = NULL;
' |) }# m: I, o7 Qm_pConnection = NULL;
9 I4 ^" L6 z# {) R4 z1 ^! e  2. 引入ADO库文件 ! H. r& j# q( o6 l6 E

$ j( j/ d+ |7 |  使用ADO前必须在工程的stdafx.h文件最后用直接引入符号#import引入ADO库文件,以使编译器能正确编译。代码如下:
* C6 N9 |  Z; L5 c#import "C:\Program Files\common files\system\ado\msado15.dll" no_namespace rename("EOF","adoEOF")$ p1 G( p. }+ C4 C. Z
  ADO类的定义是作为一种资源存储在ADO DLL(msado15.dll)中,在其内部称为类型库。类型库描述了自治接口,以及C++使用的COM vtable接口。当使用#import指令时,在运行时Visual C++需要从ADO DLL中读取这个类型库,并以此创建一组C++头文件。这些头文件具有.tli 和.tlh扩展名,读者可以在项目的目录下找到这两个文件。在C++程序代码中调用的ADO类要在这些文件中定义。 6 l% \  S3 W5 n( \. q
  程序的第三行指示ADO对象不使用名称空间。在有些应用程序中,由于应用程序中的对象与ADO中的对象之间可能会出现命名冲突,所以有必要使用名称空间。如果要使用名称空间,则可把第三行程序修改为: rename_namespace("AdoNS")。第四行代码将ADO中的EOF(文件结束)更名为adoEOF,以避免与定义了自己的EOF的其他库冲突。 . B7 {+ p' }# G/ P: B* w- F

2 w/ R0 O4 z4 B4 {9 W0 ]1 v. h' ]+ b  3.利用智能指针进行数据库操作 ; @9 N/ G# O4 `0 u) }
) y# E% c& I1 \0 N) J
  在CaboutDlg头文件中定义两个ADO智能指针类实例,并在对话框中加入一个ListCtrl。
" o9 A# q+ e3 r3 @' I6 w
) B: B  P' W) Q; d" `% I) \class CAdotestDlg : public CDialog/ t; ^  \5 z2 @1 Q
{! o8 E. s' d9 F8 R% v$ ]+ s6 @
    _ConnectionPtr m_pConnection;
  S) E* j4 e5 w3 i6 Y! P    _RecordsetPtr m_pRecordset;" E; n$ b# D4 L, x3 p1 X0 n& w! `+ B& C
   ClistCtrl m_List;
4 r8 C6 x* i. B7 x    ......
# P8 z2 \2 ?# p( @  h4 w}     
, H' B, a2 X& \$ z+ t9 V- i, ~& H
+ D; J  w7 d* _3 q! i2 {  ADO库包含三个智能指针:_ConnectionPtr、_CommandPtr和_RecordsetPtr。) U% N$ \- P1 A0 t
; q3 A3 ?& R7 z6 I* Z- c
  _ConnectionPtr通常被用来创建一个数据连接或执行一条不返回任何结果的SQL语句,如一个存储过程。3 k- W- A- Y; j4 m
  _CommandPtr返回一个记录集。它提供了一种简单的方法来执行返回记录集的存储过程和SQL语句。在使用_CommandPtr接口时,可以利用全局_ConnectionPtr接口,也可以在_CommandPtr接口里直接使用连接串。  _RecordsetPtr是一个记录集对象。与以上两种对象相比,它对记录集提供了更多的控制功能,如记录锁定、游标控制等。 & U- z% ~2 v8 A5 C, ~* ?& Q% a+ d  b

$ ?2 [& N. T) f. s  在使用ADO程序的事件响应中OnButton1加入以下代码:
  o8 n( y) c$ J) [
# G# W. K- f3 v! ]void CAdotestDlg::OnButton1()
$ A( s& C" p, U- j; B{
. [7 p8 o2 o$ X' h; X2 V( c! Em_List.ResetContent();
0 ]  j# d% [5 _) h5 E" X2 r( Zm_pConnection.CreateInstance(_uuidof(Connection)); //初始化Connection指针, y0 K8 f% X- _/ _
m_pRecordset.CreateInstance(_uuidof(Recordset));//初始化Recordset指针) L+ O0 w$ d  Q8 ~  x' {. Z
try
) m3 j  @% C* d) e$ c$ B3 E{2 |0 n# _, o2 e% A) j
m_pConnection->Open("DSN=ADOTest","","",0); //连接叫作ADOTest的ODBC数据源
4 |/ n* V& k5 N& j3 h9 Y3 F //注意:这是连接不需要用户ID或密码的open 函数6 _/ n$ m* X" i3 {2 F/ K% ~
// 否则形式为 ->Open("DSN=test;uid=sa;pwd=123;","","",0);
4 G1 i7 i; ?- H- b' Y) Y8 F" v* X
9 D, Y* g# D/ e! t+ K! a" v- z7 _4 j4 v, Q8 | // 执行SQL语句得到一个记录集把其指针赋值给m_pRecordset" e* Y5 `5 L) v  L
CString strSql="select * from middle";( _2 M* c9 m8 T1 T' K
BSTR bstrSQL = strSql.AllocSysString();
, d6 p8 W' i- L4 J4 i) k2 A4 X7 V m_pRecordset->Open(bstrSQL,(IDispatch*)m_pConnection,adOpenDynamic,adLockOptimistic,adCmdText);
. C! x! p8 Q! r) ` //adOpenDynamic:动态 adLockOptimistic乐观封锁法 adCmdText:文本查询语句
, c# B* y. _8 K7 _$ f: b1 v$ S while(!m_pRecordset->adoEOF)//遍历所有记录
- J% ~0 g! l) M) y4 L {
  C0 I3 C2 M" v- t4 F; p: ^  //取纪录字段值方式之一
- u/ Q5 h" e( d9 ]8 C" p1 W  _variant_t Thevalue; //VARIANT数据类型
. Y1 W+ C/ E4 E, b6 Z% C: T3 R  Thevalue = m_pRecordset->GetCollect("BIG_NAME");//得到字段BIG_NAME的值/ N$ T& D6 z5 X' k
  if(Thevalue.vt!=VT_NULL)+ ]1 E8 J1 h8 L  D0 E2 X7 M
   m_List.AddString((char*)_bstr_t(Thevalue));3 y9 f' ^- M& }9 p3 T6 b
  //将该值加入到列表控件中
3 i0 S: z4 ]. J6 ^* v; i9 l+ N- z
  //取纪录字段值方式之二
. y  i2 A* c* A  q2 ]3 G5 \/ f9 e8 k! ]$ e  // _bstr_t Thevalue1=m_pRecordset->Fields->GetItem("BIG_NAME")->value;# e6 v% i( i1 [3 S5 X. [
  // CString temp=Thevalue1.copy();8 K: N! z6 p2 q
  // m_List.AddString(temp);
7 x1 \4 O; }4 c, o  //数据类型转换% i1 U) t' i/ n/ B) {1 x
  _variant_t vUsername,vBirthday,vID,vOld;
% d+ V: o: i2 `* j; Q. r  TRACE("id:%d,姓名:%s,年龄:%d,生日:%s\r\n",
, |+ C/ D  ?! Z4 t9 N8 o1 c  vID.lVal,(LPCTSTR)(_bstr_t)vUsername,vOld.lVal,(LPCTSTR)(_bstr_t)vBirthday);
  j! c! t1 V% y( r. e( V. M: V' r+ h& Z3 Y  o. A5 h* p" _$ w1 {/ V- }
  m_pRecordset->MoveNext();//转到下一条纪录+ z5 l. N. u: q- y
}
: d  D0 c+ v& r- @' @ m_pRecordset->Close();
# f- p5 g' N7 j! H8 v7 R m_pConnection->Close();' _6 x& X( G! z' ]  f/ R
}
# B: ^0 ?7 c: ~/ Lcatch (_com_error e)//异常处理
, k/ ]3 j# A1 ~( z' B/ b: |{7 o: V" T, r& ?' r
AfxMessageBox(e.ErrorMessage());( e9 S. l& ^9 b  Z: T
}/ [4 b$ @) m) W1 q2 K
m_pRecordset->Close(); //注意!!!不要多次关闭!!!!否则会出错
( S; R; T/ d. g4 X4 Km_pConnection->Close();
0 Q! k/ r( K7 r, ~) F  nm_pRecordset = NULL;
3 w# K2 X3 }$ ^% ]6 `% Bm_pConnection = NULL; * E  z2 l0 h' c+ O7 p1 C  Y$ _
}
) {) n8 k0 \6 k2 n4 c( J# D  d. ?  _
9 o. ^7 l7 A+ x: M$ G8 g! `  程序中通过_variant_t和_bstr_t转换COM对象和C++类型的数据, _variant_t类封装了OLE自治VARIANT数据类型。在C++中使用_variant_t类要比直接使用VARIANT数据类型容易得多。 % ~, ]9 Z+ o7 s! {1 l$ q
% D' D/ v* u/ f( D; [
  好,编译后该程序就能运行了,但记住运行前要创建一个叫ADOTest的ODBC数据源。该程序将把表middle中的BIG_NAME字段值显示在列表控件中。
作者: chenlk    时间: 2005-4-9 16:35
有用




欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5