1.配置ODBC,建立ODBC和SQL SERVER的连接ODBCTEST
2.在VC++通过该ODBC调用SQL SERVER的STORED PROCEDURE(szTypes )
#include "stdafx.h"
#include "DatabaseServer.h"
#include <stdarg.h>#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////CDatabaseServer::CDatabaseServer()
{
}CDatabaseServer::~CDatabaseServer()
{}bool CDatabaseServer::getConnectionString(char *szConnectionString)
{
char szServerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD dwSize=sizeof(szServerName) ;
if(!GetComputerName(szServerName,&dwSize))
return false ;
if(!szConnectionString)
return false ; char szUserName[] = "SA";
char szPassword[] = "";
char szDatabase[] = "IPLOMA";//ADD YOU DATEBASE NAME
sprintf(szConnectionString,"DSN=ODBCTEST;uid=%s;pwd=%s;",szServerName,szDatabase,szUserName,szPassword); //建立CONNECTION STRING return true;
}VARIANT CDatabaseServer::getExecStoredProcedure(char *szTypes,SAFEARRAY *pSPFields)
{
_variant_t vtResultRows;
try
{
_CommandPtr pCmdPtr;
_RecordsetPtr pRecordset;
HRESULT hr ; hr = pCmdPtr.CreateInstance(__uuidof(Command)); char szConnectionString[255];
getConnectionString(szConnectionString);
_variant_t vtConnectionString(szConnectionString);
pCmdPtr->put_ActiveConnection(vtConnectionString); pCmdPtr->CommandType = adCmdStoredProc; //CALL SQL SP
pCmdPtr->CommandText = szTypes ; //YOU SP NAME
hr = pCmdPtr->Parameters->Refresh(); long lBound,uBound ;
HRESULT hresult ;
// Getting Safe Array's Lower and Upper Bounds
hresult = SafeArrayGetLBound(pSPFields, 1, &lBound);
hresult = SafeArrayGetUBound(pSPFields, 1, &uBound); variant_t vtParamVal;
_variant_t Index;
Index.vt = VT_I2;
Index.iVal = 1 ;
for (long iElements=lBound;iElements<=uBound;iElements++)
{
hresult = SafeArrayGetElement(pSPFields, &iElements, &vtParamVal);
pCmdPtr->GetParameters()->GetItem(Index)->PutValue(vtParamVal) ;
Index.iVal++ ;
} //Execute current Stored Procedure
_variant_t vEffected ;
pRecordset = pCmdPtr->Execute(&vEffected,NULL,NULL);
if (pRecordset->BOF || pRecordset->EndOfFile)
throw ;
// Get result set in the form of array
vtResultRows = pRecordset->GetRows(-1);
return vtResultRows.Detach() ;
}
catch(_com_error &e)
{
ATLTRACE((LPCSTR)e.Description());
}
vtResultRows.vt = VT_EMPTY ;
return vtResultRows.Detach();
}long CDatabaseServer::setExecStoredProcedure(char *szTypes,SAFEARRAY *pSPFields)
{
_variant_t vtResultRows;
try
{
_CommandPtr pCmdPtr;
_RecordsetPtr pRecordset;
HRESULT hr ; hr = pCmdPtr.CreateInstance(__uuidof(Command)); char szConnectionString[255];
getConnectionString(szConnectionString);
_variant_t vtConnectionString(szConnectionString);
pCmdPtr->put_ActiveConnection(vtConnectionString); pCmdPtr->CommandType = adCmdStoredProc;
pCmdPtr->CommandText = szTypes ;
hr = pCmdPtr->Parameters->Refresh(); long lBound,uBound;
HRESULT hresult;
// Getting Safe Array's Lower and Upper Bounds
hresult = SafeArrayGetLBound(pSPFields, 1, &lBound);
hresult = SafeArrayGetUBound(pSPFields, 1, &uBound); variant_t vtParamVal;
_variant_t Index;
Index.vt = VT_I2;
Index.iVal = 1 ;
for (long iElements=lBound;iElements<=uBound;iElements++)
{
hresult = SafeArrayGetElement(pSPFields, &iElements, &vtParamVal);
pCmdPtr->GetParameters()->GetItem(Index)->PutValue(vtParamVal) ;
Index.iVal++ ;
} _variant_t vEffected ;
pCmdPtr->Execute(&vEffected,NULL,NULL);
// We Are Expecting That Stored Procedures Return ID for Entity to which
// NSERT/UPDATE/DELETE operation is being performed
return (long)pCmdPtr->Parameters->Item["RETURN_VALUE"]->Value ;
}
catch(_com_error &e)
{
ATLTRACE((LPCSTR)e.Description());
}
return 0;
}
2.在VC++通过该ODBC调用SQL SERVER的STORED PROCEDURE(szTypes )
#include "stdafx.h"
#include "DatabaseServer.h"
#include <stdarg.h>#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////CDatabaseServer::CDatabaseServer()
{
}CDatabaseServer::~CDatabaseServer()
{}bool CDatabaseServer::getConnectionString(char *szConnectionString)
{
char szServerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD dwSize=sizeof(szServerName) ;
if(!GetComputerName(szServerName,&dwSize))
return false ;
if(!szConnectionString)
return false ; char szUserName[] = "SA";
char szPassword[] = "";
char szDatabase[] = "IPLOMA";//ADD YOU DATEBASE NAME
sprintf(szConnectionString,"DSN=ODBCTEST;uid=%s;pwd=%s;",szServerName,szDatabase,szUserName,szPassword); //建立CONNECTION STRING return true;
}VARIANT CDatabaseServer::getExecStoredProcedure(char *szTypes,SAFEARRAY *pSPFields)
{
_variant_t vtResultRows;
try
{
_CommandPtr pCmdPtr;
_RecordsetPtr pRecordset;
HRESULT hr ; hr = pCmdPtr.CreateInstance(__uuidof(Command)); char szConnectionString[255];
getConnectionString(szConnectionString);
_variant_t vtConnectionString(szConnectionString);
pCmdPtr->put_ActiveConnection(vtConnectionString); pCmdPtr->CommandType = adCmdStoredProc; //CALL SQL SP
pCmdPtr->CommandText = szTypes ; //YOU SP NAME
hr = pCmdPtr->Parameters->Refresh(); long lBound,uBound ;
HRESULT hresult ;
// Getting Safe Array's Lower and Upper Bounds
hresult = SafeArrayGetLBound(pSPFields, 1, &lBound);
hresult = SafeArrayGetUBound(pSPFields, 1, &uBound); variant_t vtParamVal;
_variant_t Index;
Index.vt = VT_I2;
Index.iVal = 1 ;
for (long iElements=lBound;iElements<=uBound;iElements++)
{
hresult = SafeArrayGetElement(pSPFields, &iElements, &vtParamVal);
pCmdPtr->GetParameters()->GetItem(Index)->PutValue(vtParamVal) ;
Index.iVal++ ;
} //Execute current Stored Procedure
_variant_t vEffected ;
pRecordset = pCmdPtr->Execute(&vEffected,NULL,NULL);
if (pRecordset->BOF || pRecordset->EndOfFile)
throw ;
// Get result set in the form of array
vtResultRows = pRecordset->GetRows(-1);
return vtResultRows.Detach() ;
}
catch(_com_error &e)
{
ATLTRACE((LPCSTR)e.Description());
}
vtResultRows.vt = VT_EMPTY ;
return vtResultRows.Detach();
}long CDatabaseServer::setExecStoredProcedure(char *szTypes,SAFEARRAY *pSPFields)
{
_variant_t vtResultRows;
try
{
_CommandPtr pCmdPtr;
_RecordsetPtr pRecordset;
HRESULT hr ; hr = pCmdPtr.CreateInstance(__uuidof(Command)); char szConnectionString[255];
getConnectionString(szConnectionString);
_variant_t vtConnectionString(szConnectionString);
pCmdPtr->put_ActiveConnection(vtConnectionString); pCmdPtr->CommandType = adCmdStoredProc;
pCmdPtr->CommandText = szTypes ;
hr = pCmdPtr->Parameters->Refresh(); long lBound,uBound;
HRESULT hresult;
// Getting Safe Array's Lower and Upper Bounds
hresult = SafeArrayGetLBound(pSPFields, 1, &lBound);
hresult = SafeArrayGetUBound(pSPFields, 1, &uBound); variant_t vtParamVal;
_variant_t Index;
Index.vt = VT_I2;
Index.iVal = 1 ;
for (long iElements=lBound;iElements<=uBound;iElements++)
{
hresult = SafeArrayGetElement(pSPFields, &iElements, &vtParamVal);
pCmdPtr->GetParameters()->GetItem(Index)->PutValue(vtParamVal) ;
Index.iVal++ ;
} _variant_t vEffected ;
pCmdPtr->Execute(&vEffected,NULL,NULL);
// We Are Expecting That Stored Procedures Return ID for Entity to which
// NSERT/UPDATE/DELETE operation is being performed
return (long)pCmdPtr->Parameters->Item["RETURN_VALUE"]->Value ;
}
catch(_com_error &e)
{
ATLTRACE((LPCSTR)e.Description());
}
return 0;
}
{return _T("[BasicData],[MainSize]");}---- 对 于GetDefaultSQL() 函 数 返 回 的 表 名, 对 应 的 缺 省 操 作 是SELECT 语 句, 即: SELECT * FROM BasicData,MainSize---- 查 询 过 程 中 也 可 以 利 用CRecordSet 的 成 员 变 量m_strFilter 和m_strSort 来 执 行 条 件 查 询 和 结 果 排 序。m_strFilter 为 过 滤 字 符 串, 存 放 着SQL 语 句 中WHERE 后 的 条 件 串;m_strSort 为 排 序 字 符 串, 存 放 着SQL 语 句 中ORDER BY 后 的 字 符 串。 如: Super_ESSet.m_strFilter="TYPE='电动机'";
Super_ESSet.m_strSort="VOLTAGE";
Super_ESSet.Requery();
对应的SQL语句为:
SELECT * FROM BasicData,MainSize
WHERE TYPE='电动机'
ORDER BY VOLTAGE---- 除 了 直 接 赋 值 给m_strFilter 以 外, 还 可 以 使 用 参 数 化。 利 用 参 数 化 可 以 更 直 观, 更 方 便 地 完 成 条 件 查 询 任 务。 使 用 参 数 化 的 步 骤 如 下: ---- (1) . 声 明 参 变 量: CString p1;
float p2;---- (2) . 在 构 造 函 数 中 初 始 化 参 变 量 p1=_T("");
p2=0.0f;
m_nParams=2;---- (3) . 将 参 变 量 与 对 应 列 绑 定 pFX- >SetFieldType(CFieldExchange::param)
RFX_Text(pFX,_T("P1"),p1);
RFX_Single(pFX,_T("P2"),p2);---- 完 成 以 上 步 骤 之 后 就 可 以 利 用 参 变 量 进 行 条 件 查 询 了: m_pSet- >m_strFilter="TYPE=? AND VOLTAGE=?";
m_pSet- >p1=" 电 动 机";
m_pSet- >p2=60.0;
m_pSet- >Requery();---- 参 变 量 的 值 按 绑 定 的 顺 序 替 换 查 询 字 串 中 的"?" 适 配 符。 ---- 如 果 查 询 的 结 果 是 多 条 记 录 的 话, 可 以 用CRecordSet 类 的 函 数Move(),MoveNext(),MovePrev(),MoveFirst() 和MoveLast() 来 移 动 光 标。 ---- 2 . 增 加 记 录 ---- 增 加 记 录 使 用AddNew() 函 数, 要 求 数 据 库 必 须 是 以 允 许 增 加 的 方 式 打 开: m_pSet- >AddNew(); //在表的末尾增加新记录
m_pSet- >SetFieldNull(&(m_pSet- >m_type), FALSE);
m_pSet- >m_type=" 电 动 机";
... //输入新的字段值
m_pSet- > Update(); //将新记录存入数据库
m_pSet- >Requery(); //重建记录集---- 3 . 删 除 记 录 ---- 直 接 使 用Delete() 函 数, 并 且 在 调 用Delete() 函 数 之 后 不 需 调 用Update() 函 数: m_pSet- >Delete();
if (!m_pSet- >IsEOF())
m_pSet- >MoveNext();
else
m_pSet- >MoveLast();---- 4 . 修 改 记 录 ---- 修 改 记 录 使 用Edit() 函 数: m_pSet- >Edit(); //修改当前记录
m_pSet- >m_type="发电机";
//修改当前记录字段值
...
m_pSet- >Update(); //将修改结果存入数据库
m_pSet- >Requery();---- 5 . 撤 消 操 作 ---- 如 果 用 户 选 择 了 增 加 或 者 修 改 记 录 后 希 望 放 弃 当 前 操 作, 可 以 在 调 用Update() 函 数 之 前 调 用: CRecordSet::Move(AFX_MOVE_REFRESH);---- 来 撤 消 增 加 或 修 改 模 式, 并 恢 复 在 增 加 或 修 改 模 式 之 前 的 当 前 记 录。 其 中 的 参 数AFX_MOVE_REFRESH 的 值 为 零。 ---- 6 . 数 据 库 连 接 的 复 用 ---- 在CRecordSet 类 中 定 义 了 一 个 成 员 变 量m_pDatabase: CDatabase* m_pDatabase;---- 它 是 指 向 对 象 数 据 库 类 的 指 针。 如 果 在CRecordSet 类 对 象 调 用Open() 函 数 之 前, 将 一 个 已 经 打 开 的CDatabase 类 对 象 指 针 传 给m_pDatabase, 就 能 共 享 相 同 的CDatabase 类 对 象。 如: CDatabase m_db;
CRecordSet m_set1,m_set2;
m_db.Open(_T("Super_ES"));//建立ODBC连接
m_set1.m_pDatabase=&m_db;
//m_set1复用m_db对象
m_set2.m_pDatabse=&m_db;
// m_set2复用m_db对象
{
TRY
{
m_pdb- >ExecuteSQL(strSQL);//直接执行SQL语句
}
CATCH (CDBException,e)
{
CString strMsg;
strMsg.LoadString(IDS_EXECUTE_SQL_FAILED);
strMsg+=strSQL;
return FALSE;
}
END_CATCH
return TRUE;
}---- 应 当 指 出 的 是, 由 于 不 同DBMS 提 供 的 数 据 操 作 语 句 不 尽 相 同, 直 接 执 行SQL 语 句 可 能 会 破 坏 软 件 的DBMS 无 关 性, 因 此 在 应 用 中 应 当 慎 用 此 类 操 作。 ---- 8 . 动 态 连 接 表 ---- 表 的 动 态 连 接 可 以 利 用 在 调 用CRecordSet::Open() 函 数 时 指 定SQL 语 句 来 实 现。 同 一 个 记 录 集 对 象 只 能 访 问 具 有 相 同 结 构 的 表, 否 则 查 询 结 果 将 无 法 与 变 量 相 对 应。 void CDB::ChangeTable()
{
if (m_pSet- >IsOpen()) m_pSet- >Close();
switch (m_id)
{
case 0:
m_pSet- >Open(AFX_DB_USE_DEFAULT_TYPE,
"SELECT * FROM SLOT0"); //连接表SLOT0
m_id=1;
break;
case 1:
m_pSet- >Open(AFX_DB_USE_DEFAULT_TYPE,
"SELECT * FROM SLOT1"); //连接表SLOT1
m_id=0;
break;
}
}---- 9 . 动 态 连 接 数 据 库 ---- 由 于 与 数 据 库 的 连 接 是 通 过CDatabase 类 对 象 来 实 现 的, 所 以 我 们 可 以 通 过 赋 与CRecordSet 类 对 象 参 数m_pDatabase 以 连 接 不 同 数 据 库 的CDatabase 对 象 指 针, 就 可 以 动 态 连 接 数 据 库。 void CDB::ChangeConnect()
{
CDatabase* pdb=m_pSet- >m_pDatabase;
pdb- >Close();
switch (m_id)
{
case 0:
if (!pdb- >Open(_T("Super_ES")))
//连接数据源Super_ES
{
AfxMessageBox("数据源Super_ES打开失败,"
"请检查相应的ODBC连接", MB_OK|MB_ICONWARNING);
exit(0);
}
m_id=1;
break;
case 1:
if (!pdb- >Open(_T("Motor")))
//连接数据源Motor
{
AfxMessageBox("数据源Motor打开失败,"
"请检查相应的ODBC连接", MB_OK|MB_ICONWARNING);
exit(0);
}
m_id=0;
break;
}
}