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;

_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());
}

使用上述方法就可以连接到你的数据库了。这里sailor建议一定要使用catch,否则如果错误了就会返回类似R6010的错误,调试都不知道问题在哪里。

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

如果有什么好的方法,或者文章中存在什么错误,请不要吝啬你的建议,给我留言,让我们一起进步。

 标签: MFC, SQL2008, VC, ADO

作者  :  sailor

仅仅看明白了还不够,能把别人给讲明白了才算及格。


  1. 路过,特意来挽救你的尊严。嘎嘎!!

    October 28th, 2011 at 11:07 am 回复
      1. sailor
        sailor

        嘿嘿~3Q~幸亏是路过,不是撸过

        October 28th, 2011 at 12:52 pm 回复
  2. MurphyL
    2#
    MurphyL

    撸过~~

    October 28th, 2011 at 07:52 pm 回复
      1. sailor
        sailor

        欢迎常来撸

        October 31st, 2011 at 12:00 am 回复
  3. 才学习V C++[face:daxiao],所以还是不懂哦。但是还是想学习下。不晓得为何我们学习C语言都是C++的环境啊。直接衍生到这个。

    October 30th, 2011 at 12:32 pm 回复
      1. sailor
        sailor

        因为C++是从c衍生出来的啊,用C++的编译器一般可以完全编译c程序

        October 31st, 2011 at 12:01 am 回复


关于我

about me

sailor

仅仅看明白了还不够,能把别人给讲明白了才算及格。

联系我

最新文章