ADO 操作小结

ADO 操作总结
#pragma once
#import "C:/Program Files/Common Files/System/ado/msado15.dll" no_namespace rename("EOF","adoEof")
#include <string>
#include <vector>

#ifdef _UNICODE
typedef std::wstring _tstring;
#else
typedef std::string _tstring;
#endif

/* 使用Recordset 注意事项 
*http://www.w3school.com.cn/ado/ado_ref_recordset.asp
*http://www.cnblogs.com/fickleness/p/3149016.html
*使用完需要close and xx.Release(); 
*	if(pRecord->State)//校验数据库是否打开
*	{
*		pRecord->Close();
*	}
*	pRecord.Release();
*Recordset 属性取决于提供者的功能和游标类型。对于仅向前游标,RecordCount 属性将返回 -1;
*对于静态或键集游标,将返回实际计数;
*而对于动态游标,则返回 -1 或实际计数,这取决于数据源。
*如果 ADO 无法确定记录数目或者提供者或游标类型不支持 RecordCount,则该属性返回 -1
*BOF,EOF属性:BOF指示当前记录位置的第一记录的前一个,EOF指示当前记录的最后一个记录的后一个
*打开 Recordset 时,如果有记录 BOF 和 EOF 属性被设置为 False。如果没有记录,BOF 和 EOF 属性设置是 True。
*State 返回一个值,此值可描述是否 Recordset 对象是打开、关闭、正在连接、正在执行或正在取回数据
*m_pRecordset->GetCollect(_variant_t(long (i))) //必须是long 否则出错 
或者VARIANT vt;
vt.vt = VT_I4;
vt.intVal = i;
或者
m_pRecordset->GetCollect("username")

m_pConnect.GetInterfacePtr();
*/
	
/*使用存储过程注意事项:
*参考文章:http://blog.csdn.net/jackalfly/article/details/8558937
*此连接对象必须被设置为:m_pConnection->CursorLocation =adUseClient
*如果不设置,那么在取return和output参数的时候,必须关闭关闭记录集以后才能取。
*否则return和output就不回取到正确的值。设成adUseClient就ok了。
*如果Execute()方法设置了游标该设置,那么Recordset 将从连接中继承该设置。
*例如:如果m_pConnection->CursorLocation=adUseClient,那么记录集也是adUseClient的了
*/

typedef struct structStoreProcParam
{
	_tstring szParamName;//> 参数名称
	DataTypeEnum DataType;//> 数据类型
	int DataSize;//> 如果是固定长度的类型,就填-1或者sizeof,如果是字符串等可变长度的就填其实际长度+1。 
	ParameterDirectionEnum Direction;//>   输入还是输出参数
	_variant_t strVal;//> 参数的值 对于Int之类的以后扩展
}structStoreProcParam;


class CAdo
{
public:
	CAdo(void);
	~CAdo(void);

	/*
	* 打开数据库,内部设置了游标类型为adUserClient
	*/
	virtual bool Open(TCHAR *szConnectString);
	
	/*
	* 执行Sql语句也可以是存储过程
	* @param szExecSql 执行的Sql语句或者存储过程
	* @param [Out]recordseffected 受影响的行数 select op 返回-1 因为没有设置游标类型
	* @param [in]Parameters 存储过程参数
	* @param [in]nCountParam 存储过程的个数,个数<=100
	* @ret _RecordsetPtr 当不适用的时候记得调用 .Release();//释放引用计数
	*/
	_RecordsetPtr Exec(TCHAR *szExecSql,VARIANT *recordseffected,CommandTypeEnum = adCmdText,structStoreProcParam *Parameters = NULL,int nCountParam = 0);

	/*
	*记录集的打开 一般对select 使用
	* @param [in]szSelectSql Select  参数
	* @param [Out]pRes 返回记录集
	* @ret 是否成功
	* 记录集使用完之后请调用 ->Close 和.Release 释放资源
	*/
	bool OpenRecorder(TCHAR *szSelectSql,_RecordsetPtr &pRes,CursorTypeEnum CursorType = adOpenStatic,LockTypeEnum LockType = adLockOptimistic);

	/*
	* 记录集其他操作根据需求扩展
	*/

	/*
	* 获取存储过程的param 的Val
	*/
	bool GetStoreProcParamVal(TCHAR *szParamName,VARIANT &val);

	/*
	* 获取记录集的Fileds
	*/
	bool GetFiledsCount(_RecordsetPtr &pRes,long *lFiledsCount);
	bool GetFileds(_RecordsetPtr &pRes,std::vector<_tstring> &vTitle);

	/*
	* 获取某记录集的个数 select count(*) from 
	*/
	bool GetRecordSetCount(TCHAR *szExeSql,long &lcout);

	/*
	* 获取错误信息
	*/
	const TCHAR *GetLastError(){return m_LastError;};
private:
	_ConnectionPtr m_pConnect;
	//_RecordsetPtr m_pRecorderset;
	_CommandPtr m_pCommand;
	TCHAR m_LastError[1024];
};



//ADO.cpp#include "StdAfx.h"

#include "StdAfx.h"
#include "Ado.h"
#include <assert.h>

#define ADOERR(err)\
_tcscpy_s(m_LastError,1024,err);

CAdo::CAdo(void)
{
	memset(m_LastError,0,sizeof(TCHAR)*1024);
	HRESULT hr = m_pConnect.CreateInstance(_T("ADODB.Connection"));
	assert(SUCCEEDED(hr));
	hr = m_pCommand.CreateInstance(_T("ADODB.Command"));
	assert(SUCCEEDED(hr));
// 	hr = m_pRecorderset.CreateInstance(_T("ADODB.Recordset"));
// 	assert(SUCCEEDED(hr));
}


CAdo::~CAdo(void)
{
	///> 如果没有Open 不知道为嘛Connect会崩溃
	if(m_pConnect)
	{
		///> 如果数据库已经打开则关闭
		if(m_pConnect->State)
			m_pConnect->Close();
		m_pCommand.Release();
		m_pConnect = NULL;
	}
	if(m_pCommand)
	{
		m_pCommand.Release();
		m_pCommand = NULL;
	}
}

bool CAdo::Open(TCHAR *szConnectString)
{
	try
	{
		if(m_pConnect)
		{
			//> 不知道为嘛超时值不起作用
			//m_pConnect->ConnectionTimeout = 15;
			m_pConnect->ConnectionString = szConnectString;
			HRESULT hr = m_pConnect->Open("","","",adConnectUnspecified);
			if(SUCCEEDED(hr))
			{
				///> 设置游标类型
				m_pConnect->put_CursorLocation(adUseClient);
				return true;
			}
		}
	}
	catch(_com_error e)
	{
		ADOERR(e.ErrorMessage());
		return false;
	}

	return false;
}

_RecordsetPtr CAdo::Exec(TCHAR *szExecSql,VARIANT *recordseffected,CommandTypeEnum cmdtype,structStoreProcParam *Parameters,int nCountParam)
{
	///> 数据库连接一定存在而且打开
	try
	{
		if(m_pConnect && m_pConnect->State)
		{
			///>  使用Command 来执行命令
			m_pCommand->ActiveConnection = m_pConnect;
			m_pCommand->CommandText = (_bstr_t)szExecSql;
			m_pCommand->CommandType = cmdtype;

			///> 设置参数
			///m_paramOUT=m_CommandPtr->CreateParameter("OUTPARAM",adInteger,adParamOutput,sizeof(int),(_variant_t)(long)0);
			_ParameterPtr param[100];
			for (int i = 0;i < nCountParam;++i)
			{
				param[i] = m_pCommand->CreateParameter(Parameters[i].szParamName.c_str(),Parameters[i].DataType,Parameters[i].Direction,Parameters[i].DataSize,Parameters[i].strVal);
				m_pCommand->Parameters->Append(param[i]); 
			}
			return m_pCommand->Execute(recordseffected,NULL,cmdtype);
		}
	}
	catch(_com_error e)
	{
		ADOERR(e.ErrorMessage());
	}
	return NULL;
}

bool CAdo::OpenRecorder(TCHAR *szSelectSql,_RecordsetPtr &pRes,CursorTypeEnum CursorType,LockTypeEnum LockType)
{
	try
	{
		pRes.CreateInstance(_T("ADODB.Recordset"));
		if(pRes)
		{
			HRESULT hr = pRes->Open(szSelectSql,m_pConnect.GetInterfacePtr(),CursorType,LockType,adCmdText);
			if(SUCCEEDED(hr))
				return true;
		}
	}
	catch(_com_error e)
	{
		ADOERR(e.ErrorMessage());
	}
	return false;
}

bool CAdo::GetStoreProcParamVal(TCHAR *szParamName,VARIANT &val)
{
	try
	{
		if(m_pCommand)
		{
			val =  m_pCommand->Parameters->GetItem(szParamName)->GetValue();
			return true;
		}
	}
	catch(_com_error e)
	{
		ADOERR(e.ErrorMessage());
	}
	return false;
	
}

bool CAdo::GetRecordSetCount(TCHAR *szExeSql,long &lcout)
{
	VARIANT vt;
	vt.vt = VT_I4;
	vt.intVal = 0;
	_RecordsetPtr prs = Exec(szExeSql,&vt);
	if(prs)
	{
		try
		{
			///> 获取第一个字段的值
			_variant_t vCount = prs->GetCollect((_variant_t)(long)0);
			lcout = vCount.lVal;
			prs.Release();
			return true;
		}
		catch(_com_error e)
		{
			prs.Release();
			ADOERR(e.ErrorMessage());
		}
	}
	return false;
}

bool CAdo::GetFiledsCount(_RecordsetPtr &pRes,long *lFiledsCount)
{
	try
	{
		HRESULT hr = pRes->Fields->get_Count(lFiledsCount);
		if(SUCCEEDED(hr))
			return true;
	}
	catch(_com_error e)
	{
		ADOERR(e.ErrorMessage());
	}
	return false;
}

bool CAdo::GetFileds(_RecordsetPtr &pRes,std::vector<_tstring> &vTitle)
{
	try
	{
		vTitle.clear();
		///> 记录集为空
		if(pRes->BOF)
		{
			return true;
		}
		long lfileds = 0;
		HRESULT hr = pRes->Fields->get_Count(&lfileds);
		if(FAILED(hr))
			return false;

		for (int i = 0;i < lfileds;++i)
		{
			VARIANT Vt;
			Vt.vt = VT_I4;
			Vt.intVal = i;
			_tstring strName = pRes->Fields->GetItem(&Vt)->Name;
			vTitle.push_back(strName);
		}
		return true;
	}
	catch(_com_error e)
	{
		ADOERR(e.ErrorMessage());
	}
	return false;
}

测试文件
//test.cpp

// test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<iostream>
#include <Windows.h>
#include <string>
#include <windows.h>
#include "Dump.h"
#include "Ado.h"
#include <vector>
using namespace std;


void PrintRecord(CAdo &ado,_RecordsetPtr &prs)
{
	if(!prs->State) return;
	long lcountItem = 0;
	ado.GetFiledsCount(prs,&lcountItem);
	std::vector<_tstring> vTitle;
	ado.GetFileds(prs,vTitle);
	for (int i = 0;i < vTitle.size();++i)
	{
		wcout<<vTitle[i].c_str()<<"	"; 
	}

	cout<<endl;
	while(!prs->adoEof)
	{                     
		for(int i = 0;i < lcountItem;++i)                      
		{                      
			VARIANT vt;
			vt.vt = VT_I4;
			vt.intVal = i;

			if(prs->GetCollect(_variant_t(long (i))).vt !=VT_NULL)                           
			{    
				cout<<(_bstr_t)prs->GetCollect(vt)<<" ";                           
			}                           
			else  
			{  
				cout<<"NULL"<<endl;    
			}                    
		}  
		cout<<endl;
		prs->MoveNext();
	}
}

void main()
{
	::CoInitialize(NULL);
	CAdo ado;
	bool bOpen = ado.Open(_T("Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=test;Data Source=CAIR"));
	if(bOpen)
	{
		long lcout = 0;
		bool bRet = ado.GetRecordSetCount(_T("select count(*) from Student"),lcout);
		VARIANT vt;
		vt.vt = VT_I4;
		vt.intVal = 0;
		//_RecordsetPtr prs = ado.Exec(_T("select * from Student"),&vt);
		///> 执行存储过程
		structStoreProcParam param[3];
		param[0].Direction = adParamInput;
		param[0].DataType = adVarWChar;
		param[0].DataSize = 4;
		param[0].szParamName = _T("sname");
		param[0].strVal = _T("jfm");


		param[1].Direction = adParamInput;
		param[1].DataType = adInteger;
		param[1].DataSize = -1;
		param[1].strVal = 20;
		param[1].szParamName = _T("Sage");

		param[2].Direction = adParamOutput;
		param[2].DataType = adInteger;
		param[2].DataSize = -1;
		param[2].strVal = 0;
		param[2].szParamName = _T("IsRight");

		///> 执行存储过程
		cout<<"执行存储过程StuProc3 结果:"<<endl;
		_RecordsetPtr prs = ado.Exec(_T("StuProc3"),&vt,adCmdStoredProc,param,3);;//ado.Exec(_T("StuProc3"),&vt,adCmdStoredProc,param,3);

		///> 获取存储结果输入输出参数
		VARIANT val;
		ado.GetStoreProcParamVal(_T("sname"),val);
		ado.GetStoreProcParamVal(_T("IsRight"),val);
		if(val.intVal != 0)
		{
			cout<<"SName:jfm Sage:20"<<"数据库存在该项!"<<endl;
		}
		else
		{
			cout<<"SName:jfm Sage:20"<<"数据库不存在该项!"<<endl;
		}

		PrintRecord(ado,prs);
		if(prs->State)
		{
			prs->Close();	
		}	
		prs.Release();
		///> 打开记录集
		cout<<"执行打开记录集:select * from Student"<<endl;
		_RecordsetPtr pRecord;
		bRet = ado.OpenRecorder(_T("select * from Student"),pRecord);
		PrintRecord(ado,pRecord);
		if(pRecord->State)
		{
			pRecord->Close();
		}
		pRecord.Release();
	}

	::CoUninitialize();
}

//>> ADO 执行结果:

ADO 操作小结