VC++ADO编程小记
接触了ADO编程,是在VC++的环境下通过ADO去调用MS-SQLSERVER的数据库。尽管ADO是在OLE DB的基础上做了一定的封装,但是对于我这种小白来说掌握起来还是有一点的吃力。于是在这里记录下一点关于VC下ADO的一点心得。
ADO必备知识
ADO中最重要的对象有三个:Connection、Command和Recordset,它们分别表示连接对象、命令对象和记录集对象。_ConnectionPtr接口返回一个记录集或一个空指针。通常使用它来创建一个数据连接或执行一条不返回任何结果的SQL语句,如一个存储过程。使用_ConnectionPtr接口返回一个记录集不是一个好的使用方法。对于要返回记录的操作通常用_RecordserPtr来实现。而用_ConnectionPtr操作时要想得到记录条数得遍历所有记录,而用_RecordserPtr时不需要。
_CommandPtr接口返回一个记录集。它提供了一种简单的方法来执行返回记录集的存储过程和SQL语句。在使用_CommandPtr接口时,你可以利用全局_ConnectionPtr接口,也可以在_CommandPtr接口里直接使用连接串。如果你只执行一次或几次数据访问操作,后者是比较好的选择。但如果你要频繁访问数据库,并要返回很多记录集,那么,你应该使用全局_ConnectionPtr接口创建一个数据连接,然后使用_CommandPtr接口执行存储过程和SQL语句。
_RecordsetPtr是一个记录集对象。与以上两种对象相比,它对记录集提供了更多的控制功能,如记录锁定,游标控制等。同_CommandPtr接口一样,它不一定要使用一个已经创建的数据连接,可以用一个连接串代替连接指针赋给_RecordsetPtr的connection成员变量,让它自己创建数据连接。如果你要使用多个记录集,最好的方法是同Command对象一样使用已经创建了数据连接的全局_ConnectionPtr接口,然后使用_RecordsetPtr执行存储过程和SQL语句。
使用ADO前的准备
1.引入ADO库文件#import "C:\Program Files\common files\system\ado\msado15.dll" no_namespace rename("EOF","EndOfFile") rename("BOF","FirstOfFile")2.初始化OLE/COM环境
::CoInitialize(NULL);// 初始化OLE/COM库环境ADO连接MS-SQLSERVER
_ConnectionPtr pMyConnect=NULL; HRESULT hr=pMyConnect.CreateInstance(__uuidof(Connection))); if(FAILED(hr))return;使用上述方法就可以连接到你的数据库了。这里sailor建议一定要使用catch,否则如果错误了就会返回类似R6010的错误,调试都不知道问题在哪里。_bstr_t strConnect=“Provider=SQLOLEDB; Server=server_name;Database=database_name; uid=user_name; pwd=password;”; //连接数据库,一定要使用try和catch,否则即使出错也无法知道错误 try{pMyConnect->Open(strConnect,"","",NULL);} catch (_com_error &e) { AfxMessageBox(e.Description()); }
ADO定义_RecordsetPtr型变量,并打开数据集
定义_RecordsetPtr型变量,然后通过它调用Recordset对象的Open方法,即可打开一个数据集。示例
_RecordsetPtr m_pRecordset; if(FAILED(m_pRecordset.CreateInstance( __uuidof( Recordset )))) { return; } try{ m_pRecordset->Open(_variant_t("mytable"), _variant_t((IDispatch *)pMyConnect,true), adOpenKeyset, adLockOptimistic, adCmdTable); } catch (_com_error e) { AfxMessageBox(e.Description()); }
Recordset对象的Open方法非常重要,它的第一个参数可以是一个SQL语句、一个表的名字或一个命令对象等等;第二个参数就是前面建立的连接对象的指针。此外,用Connection和Command对象的Execute方法也能得到记录集,但是只读的。
读取记录的数据
示例方法try{ m_pRecordset->MoveFirst(); while(m_pRecordset->adoEOF==VARIANT_FALSE) { //Retrieve column's value: CString sName=(char*)(_bstr_t)(m_pRecordset->Fields->GetItem (_variant_t("name"))->Value); short cAge=(short)(m_pRecordset->Fields->GetItem (_variant_t("age"))->Value); //Do something what you want to do: ...... m_pRecordset->MoveNext(); } } catch (_com_error e) { AfxMessageBox(e.Description()); }本例中的name和age都是字段名,读取的字段值分别保存在sName和cAge变量内。例中的Fields是Recordset对象的容器,GetItem方法返回的是Field对象,而Value则是Field对象的一个属性(即该字段的值)。通过此例,应掌握操纵对象属性的方法。例如,要获得Field 对象的Value属性的值可以直接用属性名Value来引用它(如上例),但也可以调用Get方法,例如:
CString sName=(char*)(_bstr_t)(m_pRecordset->Fields->GetItem (_variant_t("name"))->GetValue());
通过ADO修改数据
方法一:改变了Value属性的值,即改变了字段的值。try{ m_pRecordset->MoveFirst(); while(m_pRecordset->adoEOF==VARIANT_FALSE) { m_pRecordset->Fields->GetItem (_variant_t("姓名"))->Value=_bstr_t("赵薇"); ...... m_pRecordset->Update();方法二:m_pRecordset->MoveNext(); } } catch (_com_error e) { AfxMessageBox(e.Description()); }
m_pRecordset->Fields->GetItem (_variant_t("姓名"))->PutValue(_bstr_t("赵薇"));
通过ADO添加记录
新记录添加成功后,即自动成为当前记录。AddNew方法有两种形式,一个含有参数,而另一个则不带参数。方法一(不带参数): 这种方法弄完了还要调用Update()。
try{ if(!m_pRecordset->Supports(adAddNew)) return; m_pRecordset->AddNew(); m_pRecordset->Fields->GetItem (_variant_t("姓名"))->Value=_bstr_t("赵薇"); m_pRecordset->Fields->GetItem (_variant_t("性别"))->Value=_bstr_t("女"); m_pRecordset->Fields->GetItem (_variant_t("age"))->Value=_variant_t((short)20); m_pRecordset->Fields->GetItem (_variant_t("marry"))->Value=_bstr_t("未婚"); m_pRecordset->Update(); } catch (_com_error e) { AfxMessageBox(e.Description()); }
方法二(带参数): 这种方法不需要调用Update,因为添加后,ADO会自动调用它。此方法主要是使用SafeArray挺麻烦。
_variant_t varName[4],narValue[4]; varName[0] = L"姓名"; varName[1] = L"性别"; varName[2] = L"age"; varName[3] = L"marry"; narValue[0]=_bstr_t("赵薇"); narValue[1]=_bstr_t("女"); narValue[2]=_variant_t((short)20); narValue[3]=_bstr_t("未婚"); const int nCrit = sizeof varName / sizeof varName[0]; // Create SafeArray Bounds and initialize the array SAFEARRAYBOUND rgsaName[1],rgsaValue[1]; rgsaName[0].lLbound = 0; rgsaName[0].cElements = nCrit; SAFEARRAY *psaName = SafeArrayCreate( VT_VARIANT, 1, rgsaName ); rgsaValue[0].lLbound = 0; rgsaValue[0].cElements = nCrit; SAFEARRAY *psaValue = SafeArrayCreate( VT_VARIANT, 1, rgsaValue ); // Set the values for each element of the array HRESULT hr1=S_OK.hr2=S_OK; for( long i = 0 ; i < nCrit && SUCCEEDED( hr1 ) && SUCCEEDED( hr2 );i++) { hr1=SafeArrayPutElement(psaName, &i,&varName[i]); hr2=SafeArrayPutElement(psaValue, &i,&narValue[i]); } // Initialize and fill the SafeArray VARIANT vsaName,vsaValue; vsaName.vt = VT_VARIANT │ VT_ARRAY; vsaValue.vt = VT_VARIANT │ VT_ARRAY; V_ARRAY(&vsaName) = psaName;//&vsaName->parray=psaName; //see definition in oleauto.h file. V_ARRAY(&vsaValue) = psaValue; // Add a new record: m_pRecordset->AddNew(vsaName,vsaValue);
利用ADO删除记录
调用Recordset的Delete方法就行了,删除的是当前记录。下面是示例代码:try{ m_pRecordset->MoveFirst(); while(m_pRecordset->adoEOF==VARIANT_FALSE) { CString sName=(char*)(_bstr_t)(m_pRecordset->Fields->GetItem (_variant_t("姓名"))->Value); if(::MessageBox(NULL,"姓名="+sName+"\n删除她吗?", "提示",MB_YESNO │ MB_ICONWARNING)==IDYES) { m_pRecordset->Delete(adAffectCurrent); m_pRecordset->Update(); } m_pRecordset->MoveNext(); } } catch (_com_error e) { AfxMessageBox(e.Description()); }
使用_CommandPtr接口
_CommandPtr接口返回一个Recordset对象,并且提供了更多的记录集控制功能,以下代码示例了使用_CommandPtr接口的方法:_CommandPtr pCommand; _RecordsetPtr pRs; pCommand.CreateInstance(__uuidof(Command)); pCommand->ActiveConnection=pConn; pCommand->CommandText="select * from student"; pCommand->CommandType=adCmdText; pCommand->Parameters->Refresh(); pRs=pCommand->Execute(NULL,NULL,adCmdUnknown); _variant_t varValue = pRs->GetCollect("name"); CString strValue=(char*)_bstr_t(varValue);洋洋洒洒的好大一篇,话说结束了二次开发,又开始了新的一轮的征程,静下心来做点事情吧,大三了,剩下的时间已经不多了。
文章部分内容来自:http://www.cppblog.com/ivenher/articles/2293.html http://zhidao.baidu.com/question/29009136
如果有什么好的方法,或者文章中存在什么错误,请不要吝啬你的建议,给我留言,让我们一起进步。