通过ADO访问数据库

    今天对ADO学了一下,最开始也遇到了很多的麻烦,不过后来看了网上的很多优秀的资料,学到了很多的东西,在此想总结一下,希望对有共同需求的人有一些帮助:

    ADO(Active Data Object,活动数据对象),实际上是一种基于COM(组件对象模型)的自动化接口(IDispatch)技术,并以OLE DB(对象连接和镶入的数据库)为基础,经过OLE DB精心包装后的数据库访问技术,利用它可以快速的创建数据库应用程序。 ADO提供了一组非常简单,将一般通用的数据访问细节进行封装的对象。由于ODBC数据源也提供了一般的OLE DB Privider,所以ADO不仅可以应用自身的OLE DB Privider,而且还可以应用所有的ODBC驱动程序。下面讲讲具体开发流程:

1.导入ADO

       #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,以避免和其它库中命名相冲突。在下面我们就会用到adoEOF

2.初始化COM

     导入了ADOcom组件,还必须得对其初始化,完了后还得关闭它,如下:

         CoInitialize(NULL);   //初始化

         CoUninitialize();       //关闭

     有人说,在MFC中可以用一句话执行同样的操作,如下:

        AfxOleInit();  //不过我没有试成功过,不知道是什么原因,所以最好还是用上面的那种方法吧,呵呵。

    接着,就可以直接使用ADO的操作了。我们经常使用的只是前面用#import语句引用类型库时,生成的包装类.tlh中声明的智能指针中的三个,它们分别是_ConnectionPtr_RecordsetPtr_CommandPtr。下面分别对它们的使用方法进行介绍

3.打开数据库

      _ConnectionPtr m_pConnection;//首先声明变量:

      m_pConnection.CreateInstance(__uuidof(Connection));   //实例化
      try                

// 打开数据库

        _bstr_t connectSetting="Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=CarInfo;Data Source=TR-LILAI";

      m_pConnection->Open(connectSetting,"","",adModeUnknown);         }

catch(_com_error e)

    {
     AfxMessageBox(L"
数据库连接失败,确认数据库是否在当前路径下!");

          return FALSE;

     } 

打开数据库的原型      

             HRESULT Open (

                  _bstr_t ConnectionString,   //连接字符串

                  _bstr_t UserID,            //用户号

                  _bstr_t Password,       //用户密码

                   long Options );           //连接模式              

          其中最重要的,也是最容易出错的就数  ConnectionString了,

           provider:表示数据提供者,就是我们的数据库引擎

           initial Catalog:数据库名,也可以使用database

           DataSource:数据来源,就是服务器名

 

详细的参数说明请见:

     http://blog.csdn.net/kable999/archive/2009/07/29/4391325.aspx

4.关闭数据库

   在不使用数据库的时候,则关闭库连接。如果连接状态有效,则用Close方法关闭它并赋于它空值。代码如下所示:

        if(m_pConnection->State)

              m_pConnection->Close();

          m_pConnection= NULL;

5.使用结果集(_RecordsetPtr)

_RecordsetPtr可以用来打开库内数据表,并可以对表内的记录、字段等进行各种操作。

>打开数据表。

        首先创建一个_RecordsetPtr实例,然后调用Open()得到一条SQL语句的执行结果,如下:

          _RecordsetPtr m_pRecordset;

          m_pRecordset.CreateInstance(__uuidof(Recordset));//创建实例,大家可以看到其实就是一个RecordSet

        // ADO操作中建议语句中要常用try...catch()来捕获错误信息,

        Try

           {

             m_pRecordset->Open("SELECT * FROM TestTable",    // 查询TestTable表中所有字段
             theApp.m_pConnection.GetInterfacePtr(),                 //
获取库接库的IDispatch指针

             adOpenDynamic,

             adLockOptimistic,

             adCmdText);

           }

           catch(_com_error *e)

          {

           AfxMessageBox(e->ErrorMessage());

           //其他异常处理

           }

      Open方法的原型:

       HRESULT Recordset15::Open (

             const _variant_t & Source,     //SQL查询语句

             const _variant_t & ActiveConnection, //指定已经建立好的连接

 >关闭记录集。

           直接用Close方法关闭记录集并赋于其空值。代码如下所示:

                m_pRecordset->Close();

             m_pRecordset = NULL;

 >读记录集

      还记得前面的“ rename ("EOF", "adoEOF")”吗?这里派上用场了,如下:

       CString strName;

       while(!m_pRecordset->adoEOF)   //到记录集末尾了吗?

          {

            _variant_t var = m_pRecordset->GetCollect("Name");  //获取Name列的值
  if(var.vt != VT_NULL)

                   strName = (LPCSTR)_bstr_t(var);   //_variant_t  转化为CString
               m_pRecordset->MoveNext();    //
游标下移一位

            }  

     GetCollect的原型

            inline _variant_t Recordset15::GetCollect ( const _variant_t & Index )

            index:  是一个_variant_t  类型,在这里除了使用列名外,我们也可以使用索引,如下:

                 m_pRecordset->GetCollect(_variant_t(long(0));

  >插入记录

      可以先用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条记录位置,move(1)movenext相同。

>修改记录

     可以将记录指针移动到要修改记录的位置处,直接用PutCollect(字段名,值)将新值写入,最后别忘了Update()一下下哦。

     如下:

                 try

                {

                   // 假设对第一条记录进行修改

                    m_pRecordset->MoveFirst();

                    m_pRecordset->PutCollect("Name", _variant_t(m_Name));

                    m_pRecordset->Update();

                }

               catch(_com_error *e)

                 {

                   AfxMessageBox(e->ErrorMessage());

                  }

 >删除记录

     删除记录和上面修改记录的操作类似,先将记录指针移动到要修改记录的位置,直接用Delete()方法删除它并用Update()来更新数据库既可。部分代码如下所示: 

....................

   m_pRecordset->Delete(adAffectCurrent);  // 参数adAffectCurrent为删除当前记录
  m_pRecordset->Update();

.................

 

6.执行SQL语句

    其实处理结果集,我们还有很多方式执行SQL语句。

>_CommandPtr_RecordsetPtr配合

_CommandPtr m_pCommand;

     m_pCommand.CreateInstance(__uuidof(Command));

     m_pCommand->ActiveConnection = m_pConnection;                   // 将库连接赋于它

     m_pCommand->CommandText = "SELECT * FROM TestTable";       // SQL语句 

     m_pRecordset = m_pCommand->Execute(NULL, NULL,adCmdText);  // 执行SQL语句,返回记录集

    >直接用_ConnectionPtr执行

               _RecordsetPtr Connection15::Execute ( _bstr_t CommandText,

                                                                       VARIANT * RecordsAffected,

                                                                       long Options )


               
其中CommandText是命令字串,通常是SQL命令。

                参数RecordsAffected是操作完成后所影响的行数,

                参数Options表示CommandText中内容的类型,Options可以取如下值之一:

                  adCmdText:表明CommandText是文本命令

                  adCmdTable:表明CommandText是一个表名

                  adCmdProc:表明CommandText是一个存储过程 

                  adCmdUnknown:未知

           例子:

         variant_t RecordsAffected;

         m_pConnection->Execute(

                   "UPDATE users SET old  = old+1",&RecordsAffected,adCmdText);

            

7.执行存储过程

     执行存储过程的操作和上面执行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)

      //或者直接用_ConnectionPtr调用

             variant_t RecordsAffected;

         m_pConnection->Execute( "Demo",&RecordsAffected,adCmdStoredProc);

 

 

8.遍历数据库中的所有表名

 _ConnectionPtr m_pConnect;

_RecordsetPtr pSet;

HRESULT hr;

try

hr = m_pConnect.CreateInstance("ADODB.Connection");   

if(SUCCEEDED(hr)) 

{  

CString dd;  

dd.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s",file);  

hr = m_pConnect->Open((_bstr_t)dd,"","",adModeUnknown);  

pSet = m_pConnect->OpenSchema(adSchemaTables);     

while(!(pSet->adoEOF))  

{        

//获取表格   

_bstr_t table_name = pSet->Fields->GetItem("TABLE_NAME")->Value;

//获取表格类型       

_bstr_t table_type = pSet->Fields->GetItem("TABLE_TYPE")->Value;

//过滤一下,只输出表格名称,其他的省略

if ( strcmp(((LPCSTR)table_type),"TABLE")==0){

CString tt;

tt.Format("%s",(LPCSTR)table_name);    

AfxMessageBox(tt);       

}      

pSet->MoveNext();   

}  

pSet->Close(); 

m_pConnect->Close(); 

}catch(_com_error e)///捕捉异常

CString errormessage; 

errormessage.Format("连接数据库失败!rn错误信息:%s",e.ErrorMessage());

 

AfxMessageBox(errormessage);

return -1;

}

9.遍历一个表中的所有字段

Field *   field = NULL;               
HRESULT   hr;
Fields *  fields = NULL;
hr = m_pRecordset->get_Fields (&fields);      //得到记录集的字段集和 
         
if(SUCCEEDED(hr)) 
    fields->get_Count(&ColCount);     
 
//得到记录集的字段集合中的字段的总个数        
for(i=0;iItem[i]->get_Name(&bstrColName);     //得到记录集//中的字段名
        strColName=bstrColName;        
        nameField = strColName;
        m_FieldsList.AddString(nameField);
}
if(SUCCEEDED(hr))
        fields->Release();//释放指针
其他:
1
_variant_t
(1)
、一般传给这3个指针的值都不是MFC直接支持的数据类型,而要用_variant_t转换一下
_variant_t(XX)
可以把大多数类型的变量转换成适合的类型传入:
(2)
_variant_t var;
_variant_t -> long: (long)var;
_variant_t -> CString: CString strValue = (LPCSTR)_bstr_t(var);
CString -> _variant_t: _variant_t(strSql);

2BSTR宽字符串与CString相互转换

BSTR bstr;
CString strSql;
CString -> BSTR: bstr = strSql.AllocSysString();
BSTR -> CString: strSql = (LPCSTR)bstr;

3_bstr_tCString相互转换

_bstr_t bstr;
CString strSql;
CString -> _bstr_t: bstr = (_bstr_t)strSql;
_bstr_t -> CString: strSql = (LPCSTR)bstr;

4、关于时间
Access:
表示时间的字符串#2004-4-5#
Sql:
表示时间的字符串
''2004-4-5''
DateField(
时间字段) select * from my_table where DateField > #2004-4-10#

 

 

参考资料:

 http://www.vckbase.com/document/viewdoc/?id=1215
http://hi.baidu.com/%C0%BC%D7%CF%F6%AA/blog/item/62c345de14ad671b6227985f.html
http://blog.csdn.net/b87548116/archive/2009/08/17/4454699.aspx
http://hi.baidu.com/kxkboy/blog/item/5b0553d84461af2510df9bf6.html
http://hi.baidu.com/15971/blog/item/2418131275442655f819b8b0.html

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值