分享

VC编写ADO连接Access,SQL Server数据库入门实例

 启蒙彩魂 2011-03-19

2008-09-14 19:30:22

 标签:数据库 VC MFC ADO   [推送到技术圈]

版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://orajc.blog.51cto.com/458434/99310

为了在VC中使用Ado,需要在头文件中加入以下几行代码:

#import "C:\\program files\\common files\\system\\ado\\msado15.dll" no_namespace rename("EOF", "adoEOF")

#include "adoid.h"

#include "icrsint.h"

第一行的#import语句告诉编译器把此指令中的DLL文件引入到程序中,并从库中抽取其中的对象的类信息,并产生两个头文件包含在工程中.其中的no_namespace 用来对DLL的名称域进行隔离,最后的rename,ADO中的EOF重新命名,避免和其他地方的定义的EOF产生冲突.

第三行引入的头文件定义啦ADO2.0的类和接口标识

第四行引入了ADO2.0的数据绑定扩展.

 

例子代码如下:

      //数据库连接例子

      AfxOleInit();//初始化

     

     

     

      _ConnectionPtr m_pConnection;

   //_ConnectionPtr对象用来实现和数据源的连接

      HRESULT hr = CoInitialize(NULL);

      m_pConnection.CreateInstance(__uuidof(Connection));

     

      //_bstr_t ConnectionString = "DSN=Test;UID=sa;PWD=;";//DSN---Access

     //_bstr_t ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Test.mdb";//NON_DSN---Access

      _bstr_t ConnectionString = "Provider=MSDASQL;DRIVER={SQL SERVER};SERVER=BILLGATES;DATABASE=NORTHWIND;UID=;PWD=;";//NON_DSN---SQL SERVER

      _bstr_t userName = "";

      _bstr_t password = "";

      _RecordsetPtr pRecordSet;

      _bstr_t bstrQuery("SELECT * FROM data");

      _variant_t vNull;

      vNull.vt = VT_ERROR;

      vNull.scode = DISP_E_PARAMNOTFOUND;

     

      try

      {

           m_pConnection->Open(ConnectionString,"","",adModeUnknown);

          

           hr = pRecordSet.CreateInstance(__uuidof(Recordset));

          

           if(SUCCEEDED(hr))

           {

                 pRecordSet->PutRefActiveConnection(m_pConnection);

                                  hr = pRecordSet->Open(_variant_t(bstrQuery),vNull,adOpenForwardOnly,adLockOptimistic,adCmdText);

                 AfxMessageBox("连接数据库成功!");   

                

                     

                      if(!pRecordSet->adoEOF)

                      {

                           

                            _variant_t name = pRecordSet->GetCollect("name");//获得指定列的数据

                            CString strName = (char*)_bstr_t(name);//转换数据类型

                            AfxMessageBox(strName);

                           

                            COleSafeArray vaFieldlist;//数据表字段名

                            vaFieldlist.CreateOneDim(VT_VARIANT,3);

                            long lArrayIndex[1];

                            lArrayIndex[0] = 0;

                            vaFieldlist.PutElement(lArrayIndex, &(_variant_t("name")));

                            lArrayIndex[0] = 1;

                            vaFieldlist.PutElement(lArrayIndex, &(_variant_t("age")));

                            lArrayIndex[0] = 2;

                            vaFieldlist.PutElement(lArrayIndex, &(_variant_t("address")));

                           

                           

                            COleSafeArray vaValuelist;//数据部字段值

                            vaValuelist.CreateOneDim(VT_VARIANT,3);

                            lArrayIndex[0] = 0;

                            vaValuelist.PutElement(lArrayIndex, &(_variant_t("liuy")));

                            lArrayIndex[0] = 1;

                            vaValuelist.PutElement(lArrayIndex, &(_variant_t("23")));

                            lArrayIndex[0] = 2;

                            vaValuelist.PutElement(lArrayIndex, &(_variant_t("beijing")));

                           

                            for(int i = 0; i< 2; i++)

                            {

                                  pRecordSet->AddNew(vaFieldlist,vaValuelist);//添加一行记录    

                            }

                            AfxMessageBox("添加数据成功");

                      }

           }

      }

      catch(_com_error &e)

      {

           _bstr_t bstrSource(e.Source());

           _bstr_t bstrDescription(e.Description());

       

           TRACE("Exception thrown for classes generated by #import");

           TRACE("\tCode=%O81x\n",e.Error);

           TRACE("\tCode meaning = %s\n",e.ErrorMessage);

        TRACE("\tSource = %s\n",(LPCTSTR)bstrSource);

           TRACE("\tDescription = %s\n",(LPCTSTR)bstrDescription);

          

           AfxMessageBox(e.ErrorMessage());

      }

_ConnectionPtr Open()数的意义:

ConnectionString:包含连接信息的字符串

UID:访问数据库的用户名

PSWD:访问数据库的口令

Option:可选参数

 

_RecordsetPtrOpen()函数:

HRESULT Open(const _variant_t& source, const _variant_t& conneciton, enum CursorTypeEnum curdorType, enum LockTypeEnum lockType, long options)

Source 参数是一个变体类型,她可以是一个Command的对象,SQL对象,一个表名或一个存储过程,甚至是一个URL, 一个文件名,一个流对象.

Conneciton也是一个变体类型,他可以是一个connection对象,也可以是一个指明连接目标的字符串.

cursorType指明了数据集游标的类型.她可以是以下几个值:adOpenDynamic,adOpenForwardOnly,adOpenKeyset,adOpenStatic,adOpenUnspecified.

lockType参数可以是下列值之一:adLockBachOptiomistic,adlockOptimistic,adLockPessimistic,adLockReadOnly,adLockUnspecified.

Options:参数指明了第一个参数source的类型,其值可以是adCmdUnspecified,adCmdText,

adCmdTable,adCmdStoreProc,adCmdUnknow,adCmdFile,adCmdTableDirect

//====

首先,要用#import语句来引用支持ADO的组件类型库(*.tlb),其中类型库可以作为可执行程序(DLLEXE)的一部分被定位在其自身程序中的附属资源里,如:被定位在msado15.dll的附属资源中,只需要直接用#import引用它既可。可以直接在Stdafx.h文件中加入下面语句来实现:    
   
  #import   "c:\program   files\common   files\system\ado\msado15.dll"   no_namespace   rename   ("EOF",   "adoEOF")                      
 
其中路径名可以根据自己系统安装的ADO支持文件的路径来自行设定。当编译器遇到#import语句时,它会为引用组件类型库中的接口生成包装类,#import语句实际上相当于执行了API涵数LoadTypeLib()#import语句会在工程可执行程序输出目录中产生两个文件,分别为*.tlh(类型库头文件)*.tli(类型库实现文件),它们分别为每一个接口产生智能指针,并为各种接口方法、枚举类型,CLSID等进行声明,创建一系列包装方法。语句no_namespace说明ADO对象不使用命名空间,rename   ("EOF",   "adoEOF")说明将ADO中结束标志EOF改为adoEOF,以避免和其它库中命名相冲突。  
         
其次,在程序初始过程中需要初始化组件,一般可以用CoInitialize(NULL);来实现,这种方法在结束时要关闭初始化的COM,可以用下面语句CoUnInitialize();来实现。在MFC中还可以采用另一种方法来实现初始化COM,这种方法只需要一条语句便可以自动为我们实现初始化COM和结束时关闭COM的操作,语句如下所示:   AfxOleInit();  
         
接着,就可以直接使用ADO的操作了。我们经常使用的只是前面用#import语句引用类型库时,生成的包装类.tlh中声明的智能指针中的三个,它们分别是_ConnectionPtr_RecordsetPtr_CommandPtr。下面分别对它们的使用方法进行介绍:  
  1
_ConnectionPtr智能指针,通常用于打开、关闭一个库连接或用它的Execute方法来执行一个不返回结果的命令语句(用法和_CommandPtr中的Execute方法类似)  
  ——
打开一个库连接。先创建一个实例指针,再用Open打开一个库连接,它将返回一个IUnknown的自动化接口指针。代码如下所示:   _ConnectionPtr m_pConnection;  
  //  
初始化COM,创建ADO连接等操作  
  AfxOleInit();  
  m_pConnection.CreateInstance(__uuidof(Connection));  
   
  //  
ADO操作中建议语句中要常用try...catch()来捕获错误信息,  
  //  
因为它有时会经常出现一些意想不到的错误。jingzhou   xu  
  try                                    
  {  
  //  
打开本地AccessDemo.mdb  
  m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data   Source=Demo.mdb","","",adModeUnknown);  
  }  
  catch(_com_error   e)  
  {  
  AfxMessageBox("
数据库连接失败,确认数据库Demo.mdb是否在当前路径下!");  
  return   FALSE;  
  }              
  ——
关闭一个库连接。如果连接状态有效,则用Close方法关闭它并赋于它空值。代码如下所示:   if(m_pConnection->State)  
                  m_pConnection->Close();  
  m_pConnection=   NULL;              
  2
_RecordsetPtr智能指针,可以用来打开库内数据表,并可以对表内的记录、字段等进行各种操作。  
  ——
打开数据表。打开库内表名为DemoTable的数据表,代码如下:   _RecordsetPtr m_pRecordset;  
  m_pRecordset.CreateInstance(__uuidof(Recordset));  
   
  //  
ADO操作中建议语句中要常用try...catch()来捕获错误信息,  
  //  
因为它有时会经常出现一些意想不到的错误。jingzhou   xu  
  try  
  {  
  m_pRecordset->Open("SELECT   *   FROM   DemoTable",                                 //  
查询DemoTable表中所有字段  
  theApp.m_pConnection.GetInterfacePtr(),   //  
获取库接库的IDispatch指针  
  adOpenDynamic,  
  adLockOptimistic,  
  adCmdText);  
  }  
  catch(_com_error   *e)  
  {  
  AfxMessageBox(e->ErrorMessage());  
  }              
  ——
读取表内数据。将表内数据全部读出并显示在列表框内,m_AccessList为列表框的成员变量名。如果没有遇到表结束标志adoEOF,则用GetCollect(字段名)m_pRecordset->Fields->GetItem(字段名)->Value方法,来获取当前记录指针所指的字段值,然后再用MoveNext()方法移动到下一条记录位置。代码如下所示:   _variant_t   var;  
  CString   strName,strAge;  
  try  
  {  
  if(!m_pRecordset->BOF)  
  m_pRecordset->MoveFirst();  
  else  
  {  
  AfxMessageBox("
表内数据为空");  
  return;  
  }  
   
  //  
读入库中各字段并加入列表框中  
  while(!m_pRecordset->adoEOF)  
  {  
  var   =   m_pRecordset->GetCollect("Name");  
  if(var.vt   !=   VT_NULL)  
  strName   =   (LPCSTR)_bstr_t(var);  
  var   =   m_pRecordset->GetCollect("Age");  
  if(var.vt   !=   VT_NULL)  
  strAge   =   (LPCSTR)_bstr_t(var);  
   
  m_AccessList.AddString(   strName   +   "   -->   "+strAge   );  
   
  m_pRecordset->MoveNext();  
  }  
   
  //  
默认列表指向第一项,同时移动记录指针并显示  
  m_AccessList.SetCurSel(0);  
  }  
  catch(_com_error   *e)  
  {  
  AfxMessageBox(e->ErrorMessage());  
  }            
  ——
插入记录。可以先用AddNew()方法新增一个空记录,再用PutCollect(字段名,)输入每个字段的值,最后再Update()更新到库中数据既可。其中变量m_Namem_Age分别为姓名及年龄编辑框的成员变量名。代码所下所示:   try  
  {  
  //  
写入各字段值  
  m_pRecordset->AddNew();  
  m_pRecordset->PutCollect("Name",   _variant_t(m_Name));  
  m_pRecordset->PutCollect("Age",   atol(m_Age));  
  m_pRecordset->Update();  
   
  AfxMessageBox("
插入成功!");  
  }  
  catch(_com_error   *e)  
  {  
  AfxMessageBox(e->ErrorMessage());  
  }              
  ——
移动记录指针。移动记录指针可以通过MoveFirst()方法移动到第一条记录、MoveLast()方法移动到最后一条记录、MovePrevious()方法移动到当前记录的前一条记录、MoveNext()方法移动到当前记录的下一条记录。但我们有时经常需要随意移动记录指针到任意记录位置时,可以使用Move(记录号)方法来实现,注意:   Move()方法是相对于当前记录来移动指针位置的,正值向后移动、负值向前移动,如:Move(3),当前记录是3时,它将从记录3开始往后再移动3条记录位置。代码如下所示:   try  
  {  
  int   curSel   =   m_AccessList.GetCurSel();  
  //  
先将指针移向第一条记录,然后就可以相对第一条记录来随意移动记录指针  
  m_pRecordset->MoveFirst();  
  m_pRecordset->Move(long(curSel));  
   
  }  
  catch(_com_error   *e)  
  {  
  AfxMessageBox(e->ErrorMessage());  
  }              
  ——
修改记录中字段值。可以将记录指针移动到要修改记录的位置处,直接用PutCollect(字段名,值)将新值写入并Update()更新数据库既可。可以用上面方法移动记录指针,修改字段值代码如下所示:   try  
  {  
  //  
假设对第二条记录进行修改  
  m_pRecordset->MoveFirst();  
  m_pRecordset->Move(1);                 //  
0开始  
  m_pRecordset->PutCollect("Name",   _variant_t(m_Name));  
  m_pRecordset->PutCollect("Age",   atol(m_Age));  
  m_pRecordset->Update();  
  }  
  catch(_com_error   *e)  
  {  
  AfxMessageBox(e->ErrorMessage());  
  }              
  ——
删除记录。删除记录和上面修改记录的操作类似,先将记录指针移动到要修改记录的位置,直接用Delete()方法删除它并用Update()来更新数据库既可。代码如下所示:   try  
  {  
  //  
假设删除第二条记录  
  m_pRecordset->MoveFirst();  
  m_pRecordset->Move(1);                 //  
0开始  
  m_pRecordset->Delete(adAffectCurrent);     //  
参数adAffectCurrent为删除当前记录  
  m_pRecordset->Update();  
  }  
  catch(_com_error   *e)  
  {  
  AfxMessageBox(e->ErrorMessage());  
  }              
  ——
关闭记录集。直接用Close方法关闭记录集并赋于其空值。代码如下所示:   m_pRecordset->Close();  
  m_pRecordset   =   NULL;              
  3
CommandPtr智能指针,可以使用_ConnectionPtr_RecordsetPtr来执行任务,定义输出参数,执行存储过程或SQL语句。    
  ——
执行SQL语句。先创建一个_CommandPtr实例指针,再将库连接和SQL语句做为参数,执行Execute()方法既可。代码如下所示:   _CommandPtr m_pCommand;  
  m_pCommand.CreateInstance(__uuidof(Command));  
  m_pCommand->ActiveConnection   =   m_pConnection;     //  
将库连接赋于它  
  m_pCommand->CommandText   =   "SELECT   *   FROM   DemoTable";     //   SQL
语句  
  m_pRecordset   =   m_pCommand->Execute(NULL,   NULL,adCmdText);   //  
执行SQL语句,返回记录集              
  ——
执行存储过程。执行存储过程的操作和上面执行SQL语句类似,不同点仅是CommandText参数中不再是SQL语句,而是存储过程的名字,如Demo。另一个不同点就是在Execute()中参数由adCmdText(执行SQL语句),改为adCmdStoredProc来执行存储过程。如果存储过程中存在输入、输出参数的话,需要使用到另一个智能指针_ParameterPtr来逐次设置要输入、输出的参数信息,并将其赋于_CommandPtrParameters参数来传递信息,有兴趣的读者可以自行查找相关书籍或MSDN。执行存储过程的代码如下所示:   _CommandPtr m_pCommand;  
  m_pCommand.CreateInstance(__uuidof(Command));  
      m_pCommand->ActiveConnection   =   m_pConnection;     //  
将库连接赋于它  
  m_pCommand->CommandText   =   "Demo";      
      m_pCommand->Execute(NULL,NULL,   adCmdStoredProc);              
 
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

ActiveX数据对象(ADO)是OLE   DB上面的高层数据库API。我们在C++程序中也可以调用ADO。本文将在VC   6.0环境下做一个小小的例子解释如何使用ADO    
   
 
  1.   生成应用程序框架并初始化OLE/COM库环境    
   
 
  创建一个标准的MFC   AppWizard(exe)应用程序,然后在应用程序类的InitInstance函数中初始化OLE/COM库(因为ADO库是一个COM   DLL库)。    
   
 
  BOOL   CADOTestApp::InitInstance()    
   
 
  {   //初始化OLE/COM库环境    
   
  AfxOleInit();}    
   
 
  2.   引入ADO库文件    
   
 
  使用ADO前必须在工程的stdafx.h文件里用直接引入符号#import引入ADO库文件,以使编译器能正确编译。代码如下:    
   
 
     include   comdef.h    
   
 
     import   "c:\program   files\common   files\system\ado\msado15.dll"  
   
 
     no_namespace    
   
 
     rename   ("EOF","adoEOF")    
   
 
  头文件comdef.h使我们的应用程序能够使用Visual   C++中的一些特殊COM支持类,这些类使得处理OLE自治更为容易一些,OLE自治是ADO使用的数据类型。后三行使用#import指令在我们的应用程序中输入ADO类库定义。    
   
 
  ADO类的定义是作为一种资源存储在ADO   DLL(msado15.dll)中,在其内部称为类型库。类型库描述了自治接口,以及C++使用的COM   vtable接口。当使用#import指令时,在运行时Visual   C++需要从ADO   DLL中读取这个类型库,并以此创建一组C++头文件。这些头文件具有.tli   .tlh扩展名,读者可以在项目的目录下找到这两个文件。在C++程序代码中调用的ADO类要在这些文件中定义。    
   
 
  程序的第三行指示ADO对象不使用名称空间。在有些应用程序中,由于应用程序中的对象与ADO中的对象之间可能会出现命名冲突,所以有必要使用名称空间。如果要使用名称空间,则可把第三行程序修改为:   rename_namespace("AdoNS")。第四行代码将ADO中的EOF(文件结束)更名为adoEOF,以避免与定义了自己的EOF的其他库冲突。    
   
 
  3.利用智能指针进行数据库操作    
   
 
  在CaboutDlg头文件中定义两个ADO智能指针类实例,并在对话框中加入一个ListCtrl    
   
  _ConnectionPtr   m_pConnection;    
   
  _RecordsetPtr   m_pRecordset;    
   
 
  ClistCtrl   m_List;    
   
 
  ADO库包含三个智能指针:_ConnectionPtr_CommandPtr_RecordsetPtr    
   
  _ConnectionPtr
通常被用来创建一个数据连接或执行一条不返回任何结果的SQL语句,如一个存储过程。    
   
  _CommandPtr
返回一个记录集。它提供了一种简单的方法来执行返回记录集的存储过程和SQL语句。在使用_CommandPtr接口时,可以利用全局_ConnectionPtr接口,也可以在_CommandPtr接口里直接使用连接串。    
   
  _RecordsetPtr
是一个记录集对象。与以上两种对象相比,它对记录集提供了更多的控制功能,如记录锁定、游标控制等。    
   
 
  在OnInitDialog()中加入以下代码:    
   
 
  BOOL   CAboutDlg::OnInitDialog()    
   
 
  {    
   
  CDialog::OnInitDialog();    
   
  _variant_t   TheValue;    
   
  m_List.ResetContent();    
   
 
  m_pConnection.CreateInstance(_uuidof(Connection));    
   
 
  m_pRecordset.CreateInstance(_uuidof(Recordset));    
   
 
  try{    
   
  m_pConnection->Open("DSN=ADOTest","","",0);   //
连接叫作ADOTestODBC数据源    
   
  m_pRecordset->Open("SELECT   *   FROM   BlockDefine",(IDispatch*)m_pConnection,    
  adOpenDynamic,  
  adLockOptimistic,  
  adCmdText);    
   
 
  //执行SQL语句得到一个记录集    
   
 
     while(!m_pRecordset->adoEOF)    
   
 
  //遍历所有记录    
   
 
     {    
   
 
     TheValue   =   m_pRecordset->GetCollect("BlockIndex");  
   
 
  //得到字段BlockIndex的值    
   
 
     if(TheValue.vt!=VT_NULL)    
   
 
     m_List.AddString((char*)_bstr_t(TheValue));   //将该值加入到列表控件中    
   
 
     m_pRecordset->MoveNext();    
   
 
  }    
   
 
     m_pRecordset->Close();    
   
  m_pConnection->Close();    
   
 
     }    
   
 
     catch(_com_error   e)   //异常处理    
   
 
     {    
   
  AfxMessageBox(e->ErrorMessage());    
   
 
  }    
   
 
  m_pRecordset   =   NULL;    
   
  m_pConnection   =   NULL;    
   
 
  return   TRUE;   //   return   TRUE   unless   you   set   the   focus   to   a   control    
   
 
  }    
   
 
  程序中通过_variant_t_bstr_t转换COM对象和C++类型的数据,   _variant_t类封装了OLE自治VARIANT数据类型。在C++中使用_variant_t类要比直接使用VARIANT数据类型容易得多。    
   
 
  好,编译后该程序就能运行了,但记住运行前要创建一个叫ADOTestODBC数据源。该程序将把表BlockDefine中的Bloc

 

kIndex字段值显示在列表控件中。    

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多