pDb->OpenEx(_T("DSN=daneldb;UID=sa;PWD=……"),CDatabase::noOdbcDialog);
pDbman->Open(AFX_DB_USE_DEFAULT_TYPE,"SELECT * FROM GDDJ");
后面是不是要用GetFieldValue?如何去用?有其他的方法吗?
13 个解决方案
#1
请大将帮帮忙……
up者都有分
up者都有分
#2
odbc 我不是很清楚
ado可以一次打开一个库,随便怎么操作
我估计odbc也是一样的
ado可以一次打开一个库,随便怎么操作
我估计odbc也是一样的
#3
应该是的吧
用REQUERY再试试看吧
用REQUERY再试试看吧
#4
如果用CDatabase和CRecordset直接操作数据库,SQL语句绝对是个很有用的工具。下面是个例子:
bool SomeFunc()
{
CDatabase db;
try{
db.Open("DSN=testdb;UID=sa;PWD="); //Open Database
}catch(CDBException * e)
{
e->Delete();
TRACE("Error Opening database\n");
return false;
}
CRecordset rec(&db);
try{
rec.Open(AFX_DB_USE_DEFAULT_TYPE, "select * from testtable"); //Open Rec
if(rec.IsBOF()) return false; //Return if empty
TRACE("Col1:\n----------\n");
CDBVariant value;
while(rec.IsEOF()) //Enumerate all values
{
rec.GetFieldValue("Col1",&value);
TRACE("%d\n",value.m_iVal) //if Col1 is short type value
rec.MoveNext();
}
rec.Close();
}catch(CDBException * e)
{
e->Delete();
rec.Close();
return false;
}
return true;
}
对其他表或视图可以类似处理。如果插入记录可以直接用db.ExecuteSQL。
bool SomeFunc()
{
CDatabase db;
try{
db.Open("DSN=testdb;UID=sa;PWD="); //Open Database
}catch(CDBException * e)
{
e->Delete();
TRACE("Error Opening database\n");
return false;
}
CRecordset rec(&db);
try{
rec.Open(AFX_DB_USE_DEFAULT_TYPE, "select * from testtable"); //Open Rec
if(rec.IsBOF()) return false; //Return if empty
TRACE("Col1:\n----------\n");
CDBVariant value;
while(rec.IsEOF()) //Enumerate all values
{
rec.GetFieldValue("Col1",&value);
TRACE("%d\n",value.m_iVal) //if Col1 is short type value
rec.MoveNext();
}
rec.Close();
}catch(CDBException * e)
{
e->Delete();
rec.Close();
return false;
}
return true;
}
对其他表或视图可以类似处理。如果插入记录可以直接用db.ExecuteSQL。
#5
EagleCK(),我按照您的方法……出现这样的提示,为什么?
在调用 SQLFetchScroll/SQLExtendedFetch 之前列没有绑定数据列
State:SL009,Native:0,Origin:[Microsoft][ODBC 游标库]
在调用 SQLFetchScroll/SQLExtendedFetch 之前列没有绑定数据列
State:SL009,Native:0,Origin:[Microsoft][ODBC 游标库]
#6
打一数据库后,用多个CRecordset对象就可以打开多个表呀。
#7
luckyegg(幸运蛋)
但是我在执行p_Set.Open(CRecordset::snapshot,"SELECT * FROM table");没有问题,
而在
while(!p_Set.IsEOF())
{
p_Set.GetFieldValue("id_number",varName);
Temp = varName.m_pstring->GetBuffer(100);
varName.m_pstring->ReleaseBuffer();
p_Set.MoveNext();
}
时就会提示“非法的描述器索引”或者“无效的描述器索引”
但是我在执行p_Set.Open(CRecordset::snapshot,"SELECT * FROM table");没有问题,
而在
while(!p_Set.IsEOF())
{
p_Set.GetFieldValue("id_number",varName);
Temp = varName.m_pstring->GetBuffer(100);
varName.m_pstring->ReleaseBuffer();
p_Set.MoveNext();
}
时就会提示“非法的描述器索引”或者“无效的描述器索引”
#8
Visual C++ 中 的ODBC 编 程
一 . 概 述
---- ODBC 是 一 种 使 用SQL 的 程 序 设 计 接 口。 使 用ODBC 让 应 用
程 序 的 编 写 者 避 免 了 与 数 据 源 相 联 的 复 杂 性。 这 项 技
术 目 前 已 经 得 到 了 大 多 数DBMS 厂 商 们 的 广 泛 支 持。
---- Microsoft Developer Studio 为 大 多 数 标 准 的 数 据 库 格 式 提
供 了32 位ODBC 驱 动 器。 这 些 标 准 数 据 格 式 包 括 有:
SQL Server、Access、Paradox、dBase、FoxPro、Excel、Oracle 以 及
Microsoft Text。 如 果 用 户 希 望 使 用 其 他 数 据 格 式, 用 户 需
要 相 应 的ODBC 驱 动 器 及DBMS。
---- 用 户 使 用 自 己 的DBMS 数 据 库 管 理 功 能 生 成 新 的 数 据
库 模 式 后, 就 可 以 使 用ODBC 来 登 录 数 据 源。 对 用 户 的 应
用 程 序 来 说, 只 要 安 装 有 驱 动 程 序, 就 能 注 册 很 多 不 同
的 数 据 库。 登 录 数 据 库 的 具 体 操 作 参 见 有 关ODBC 的 联 机
帮 助。
二 .MFC 提 供 的ODBC 数 据 库 类
---- Visual C++ 的MFC 基 类 库 定 义 了 几 个 数 据 库 类。 在 利
用ODBC 编 程 时, 经 常 要 使 用 到 CDatabase( 数 据 库 类),
CRecordSet( 记 录 集 类) 和CRecordView( 可 视 记 录 集 类)。 其 中:
---- CDatabase 类 对 象 提 供 了 对 数 据 源 的 连 接, 通 过 它 你
可 以 对 数 据 源 进 行 操 作。
---- CRecordSet 类 对 象 提 供 了 从 数 据 源 中 提 取 出 的 记 录 集。
CRecordSet 对 象 通 常 用 于 两 种 形 式: 动 态 行 集(dynasets) 和
快 照 集(snapshots)。 动 态 行 集 能 保 持 与 其 他 用 户 所 做 的
更 改 保 持 同 步。 快 照 集 则 是 数 据 的 一 个 静 态 视 图。 每 一
种 形 式 在 记 录 集 被 打 开 时 都 提 供 一 组 记 录, 所 不 同 的 是,
当 你 在 一 个 动 态 行 集 里 滚 动 到 一 条 记 录 时, 由 其 他 用
户 或 是 你 应 用 程 序 中 的 其 他 记 录 集 对 该 记 录 所 做 的 更
改 会 相 应 地 显 示 出 来。
---- CRecordView 类 对 象 能 以 控 制 的 形 式 显 示 数 据 库 记 录。
这 个 视 图 是 直 接 连 到 一 个CRecordSet 对 象 的 表 视 图。
三 . 应 用ODBC 编 程
---- 应 用Visual C++ 的AppWizard 可 以 自 动 生 成 一 个ODBC 应 用 程
序 框 架。 方 法 是: 打 开File 菜 单 的New 选 项, 选 取Projects,
填 入 工 程 名, 选 择MFC AppWizard (exe), 然 后 按AppWizard 的 提
示 进 行 操 作。 当AppWizard 询 问 是 否 包 含 数 据 库 支 持 时, 如
果 你 想 读 写 数 据 库, 那 么 选 定Database view with file support;
而 如 果 你 想 访 问 数 据 库 的 信 息 而 不 想 回 写 所 做 的 改 变,
那 么 选 定Database view without file support 选 项 就 比 较 合 适 了。
选 择 了 数 据 库 支 持 之 后Database Source 按 钮 会 激 活, 选 中
它 去 调 用Data Options 对 话 框。 在Database Options 对 话 框 中 会
显 示 已 向ODBC 注 册 的 数 据 库 资 源, 选 定 你 所 要 操 作 的 数
据 库, 如:Super_ES, 单 击OK 后 会 出 现Select Database Tables 对
话 框, 其 中 列 举 了 你 所 选 中 的 数 据 库 中 包 含 的 全 部 表,
选 择 你 希 望 操 作 的 表 后, 单 击OK。 在 选 定 了 数 据 库 和 数
据 表 之 后, 你 可 以 按 照 惯 例 继 续 进 行AppWizard 操 作。
---- 特 别 需 要 指 出 的 是: 在 生 成 的 应 用 程 序 框 架View 类
( 如:CSuper_ESView) 中 包 含 一 个 指 向CSuper_ESSet 对 象 的 指
针m_pSet, 该 指 针 由AppWizard 建 立, 目 的 是 在 视 表 单 和 记 录
集 之 间 建 立 联 系, 使 得 记 录 集 中 的 查 询 结 果 能 够 很 容
易 地 在 视 表 单 上 显 示 出 来。 有 关m_pSet 的 详 细 用 法 可 以
参 见Visual C++ Online Book。
---- 程 序 与 数 据 语 言 建 立 联 系, 使 用CDatebase::OpenEx() 或
CDatabase::Open() 函 数 来 进 行 初 始 化。 数 据 库 对 象 必 须 在
你 使 用 它 构 造 一 个 记 录 集 对 象 之 前 被 初 始 化。
---- 下 面 举 例 说 明 在Visual C++ 环 境 中ODBC 的 编 程 技 巧:
---- 1 . 查 询 记 录
---- 查 询 记 录 使 用CRecordSet::Open() 和CRecordSet::Requery() 成
员 函 数。 在 使 用CRecordSet 类 对 象 之 前, 必 须 使 用
CRecordSet::Open() 函 数 来 获 得 有 效 的 记 录 集。 一 旦 已 经 使
用 过CRecordSet::Open() 函 数, 再 次 查 询 时 就 可 以 应 用
CRecordSet::Requery() 函 数。 在 调 用CRecordSet::Open() 函 数 时,
如 果 已 经 将 一 个 已 经 打 开 的CDatabase 对 象 指 针 传 给
CRecordSet 类 对 象 的m_pDatabase 成 员 变 量, 则 使 用 该 数 据 库
对 象 建 立ODBC 连 接; 否 则 如 果m_pDatabase 为 空 指 针, 就 新 建
一 个CDatabase 类 对 象 并 使 其 与 缺 省 的 数 据 源 相 连, 然 后
进 行CRecordSet 类 对 象 的 初 始 化。 缺 省 数 据 源 由
GetDefaultConnect() 函 数 获 得。 你 也 可 以 提 供 你 所 需 要 的SQL
语 句, 并 以 它 来 调 用CRecordSet::Open() 函 数, 例 如:
---- Super_ESSet.Open(AFX_DATABASE_USE_DEFAULT,strSQL);
---- 如 果 没 有 指 定 参 数, 程 序 则 使 用 缺 省 的SQL 语 句, 即
对 在GetDefaultSQL() 函 数 中 指 定 的SQL 语 句 进 行 操 作:
CString CSuper_ESSet::GetDefaultSQL()
{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 对 象
---- 7 .SQL 语 句 的 直 接 执 行
---- 虽 然 通 过CRecordSet 类, 我 们 可 以 完 成 大 多 数 的 查 询
操 作, 而 且 在CRecordSet::Open() 函 数 中 也 可 以 提 供SQL 语 句,
但 是 有 的 时 候 我 们 还 想 进 行 一 些 其 他 操 作, 例 如 建 立 新
表, 删 除 表, 建 立 新 的 字 段 等 等, 这 时 就 需 要 使 用 到
CDatabase 类 的 直 接 执 行SQL 语 句 的 机 制。 通 过 调 用
CDatabase::ExecuteSQL() 函 数 来 完 成SQL 语 句 的 直 接 执 行:
BOOL CDB::ExecuteSQLAndReportFailure(const CString& strSQL)
{
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;
}
}
四 . 总 结
---- Visual C++ 中 的ODBC 类 库 可 以 帮 助 程 序 员 完 成 绝 大 多
数 的 数 据 库 操 作。 利 用ODBC 技 术 使 得 程 序 员 从 具 体 的
DBMS 中 解 脱 出 来, 从 而 极 大 的 减 少 了 软 件 开 发 的 工 作 量,
缩 短 开 发 周 期, 提 高 了 效 率 和 软 件 的 可 靠 性。 本 文 总 结
的 笔 者 从 事 软 件 开 发 的 一 些 经 验 心 得 希 望 对 从 事ODBC 开
发 的 工 作 者 有 所 帮 助。
一 . 概 述
---- ODBC 是 一 种 使 用SQL 的 程 序 设 计 接 口。 使 用ODBC 让 应 用
程 序 的 编 写 者 避 免 了 与 数 据 源 相 联 的 复 杂 性。 这 项 技
术 目 前 已 经 得 到 了 大 多 数DBMS 厂 商 们 的 广 泛 支 持。
---- Microsoft Developer Studio 为 大 多 数 标 准 的 数 据 库 格 式 提
供 了32 位ODBC 驱 动 器。 这 些 标 准 数 据 格 式 包 括 有:
SQL Server、Access、Paradox、dBase、FoxPro、Excel、Oracle 以 及
Microsoft Text。 如 果 用 户 希 望 使 用 其 他 数 据 格 式, 用 户 需
要 相 应 的ODBC 驱 动 器 及DBMS。
---- 用 户 使 用 自 己 的DBMS 数 据 库 管 理 功 能 生 成 新 的 数 据
库 模 式 后, 就 可 以 使 用ODBC 来 登 录 数 据 源。 对 用 户 的 应
用 程 序 来 说, 只 要 安 装 有 驱 动 程 序, 就 能 注 册 很 多 不 同
的 数 据 库。 登 录 数 据 库 的 具 体 操 作 参 见 有 关ODBC 的 联 机
帮 助。
二 .MFC 提 供 的ODBC 数 据 库 类
---- Visual C++ 的MFC 基 类 库 定 义 了 几 个 数 据 库 类。 在 利
用ODBC 编 程 时, 经 常 要 使 用 到 CDatabase( 数 据 库 类),
CRecordSet( 记 录 集 类) 和CRecordView( 可 视 记 录 集 类)。 其 中:
---- CDatabase 类 对 象 提 供 了 对 数 据 源 的 连 接, 通 过 它 你
可 以 对 数 据 源 进 行 操 作。
---- CRecordSet 类 对 象 提 供 了 从 数 据 源 中 提 取 出 的 记 录 集。
CRecordSet 对 象 通 常 用 于 两 种 形 式: 动 态 行 集(dynasets) 和
快 照 集(snapshots)。 动 态 行 集 能 保 持 与 其 他 用 户 所 做 的
更 改 保 持 同 步。 快 照 集 则 是 数 据 的 一 个 静 态 视 图。 每 一
种 形 式 在 记 录 集 被 打 开 时 都 提 供 一 组 记 录, 所 不 同 的 是,
当 你 在 一 个 动 态 行 集 里 滚 动 到 一 条 记 录 时, 由 其 他 用
户 或 是 你 应 用 程 序 中 的 其 他 记 录 集 对 该 记 录 所 做 的 更
改 会 相 应 地 显 示 出 来。
---- CRecordView 类 对 象 能 以 控 制 的 形 式 显 示 数 据 库 记 录。
这 个 视 图 是 直 接 连 到 一 个CRecordSet 对 象 的 表 视 图。
三 . 应 用ODBC 编 程
---- 应 用Visual C++ 的AppWizard 可 以 自 动 生 成 一 个ODBC 应 用 程
序 框 架。 方 法 是: 打 开File 菜 单 的New 选 项, 选 取Projects,
填 入 工 程 名, 选 择MFC AppWizard (exe), 然 后 按AppWizard 的 提
示 进 行 操 作。 当AppWizard 询 问 是 否 包 含 数 据 库 支 持 时, 如
果 你 想 读 写 数 据 库, 那 么 选 定Database view with file support;
而 如 果 你 想 访 问 数 据 库 的 信 息 而 不 想 回 写 所 做 的 改 变,
那 么 选 定Database view without file support 选 项 就 比 较 合 适 了。
选 择 了 数 据 库 支 持 之 后Database Source 按 钮 会 激 活, 选 中
它 去 调 用Data Options 对 话 框。 在Database Options 对 话 框 中 会
显 示 已 向ODBC 注 册 的 数 据 库 资 源, 选 定 你 所 要 操 作 的 数
据 库, 如:Super_ES, 单 击OK 后 会 出 现Select Database Tables 对
话 框, 其 中 列 举 了 你 所 选 中 的 数 据 库 中 包 含 的 全 部 表,
选 择 你 希 望 操 作 的 表 后, 单 击OK。 在 选 定 了 数 据 库 和 数
据 表 之 后, 你 可 以 按 照 惯 例 继 续 进 行AppWizard 操 作。
---- 特 别 需 要 指 出 的 是: 在 生 成 的 应 用 程 序 框 架View 类
( 如:CSuper_ESView) 中 包 含 一 个 指 向CSuper_ESSet 对 象 的 指
针m_pSet, 该 指 针 由AppWizard 建 立, 目 的 是 在 视 表 单 和 记 录
集 之 间 建 立 联 系, 使 得 记 录 集 中 的 查 询 结 果 能 够 很 容
易 地 在 视 表 单 上 显 示 出 来。 有 关m_pSet 的 详 细 用 法 可 以
参 见Visual C++ Online Book。
---- 程 序 与 数 据 语 言 建 立 联 系, 使 用CDatebase::OpenEx() 或
CDatabase::Open() 函 数 来 进 行 初 始 化。 数 据 库 对 象 必 须 在
你 使 用 它 构 造 一 个 记 录 集 对 象 之 前 被 初 始 化。
---- 下 面 举 例 说 明 在Visual C++ 环 境 中ODBC 的 编 程 技 巧:
---- 1 . 查 询 记 录
---- 查 询 记 录 使 用CRecordSet::Open() 和CRecordSet::Requery() 成
员 函 数。 在 使 用CRecordSet 类 对 象 之 前, 必 须 使 用
CRecordSet::Open() 函 数 来 获 得 有 效 的 记 录 集。 一 旦 已 经 使
用 过CRecordSet::Open() 函 数, 再 次 查 询 时 就 可 以 应 用
CRecordSet::Requery() 函 数。 在 调 用CRecordSet::Open() 函 数 时,
如 果 已 经 将 一 个 已 经 打 开 的CDatabase 对 象 指 针 传 给
CRecordSet 类 对 象 的m_pDatabase 成 员 变 量, 则 使 用 该 数 据 库
对 象 建 立ODBC 连 接; 否 则 如 果m_pDatabase 为 空 指 针, 就 新 建
一 个CDatabase 类 对 象 并 使 其 与 缺 省 的 数 据 源 相 连, 然 后
进 行CRecordSet 类 对 象 的 初 始 化。 缺 省 数 据 源 由
GetDefaultConnect() 函 数 获 得。 你 也 可 以 提 供 你 所 需 要 的SQL
语 句, 并 以 它 来 调 用CRecordSet::Open() 函 数, 例 如:
---- Super_ESSet.Open(AFX_DATABASE_USE_DEFAULT,strSQL);
---- 如 果 没 有 指 定 参 数, 程 序 则 使 用 缺 省 的SQL 语 句, 即
对 在GetDefaultSQL() 函 数 中 指 定 的SQL 语 句 进 行 操 作:
CString CSuper_ESSet::GetDefaultSQL()
{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 对 象
---- 7 .SQL 语 句 的 直 接 执 行
---- 虽 然 通 过CRecordSet 类, 我 们 可 以 完 成 大 多 数 的 查 询
操 作, 而 且 在CRecordSet::Open() 函 数 中 也 可 以 提 供SQL 语 句,
但 是 有 的 时 候 我 们 还 想 进 行 一 些 其 他 操 作, 例 如 建 立 新
表, 删 除 表, 建 立 新 的 字 段 等 等, 这 时 就 需 要 使 用 到
CDatabase 类 的 直 接 执 行SQL 语 句 的 机 制。 通 过 调 用
CDatabase::ExecuteSQL() 函 数 来 完 成SQL 语 句 的 直 接 执 行:
BOOL CDB::ExecuteSQLAndReportFailure(const CString& strSQL)
{
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;
}
}
四 . 总 结
---- Visual C++ 中 的ODBC 类 库 可 以 帮 助 程 序 员 完 成 绝 大 多
数 的 数 据 库 操 作。 利 用ODBC 技 术 使 得 程 序 员 从 具 体 的
DBMS 中 解 脱 出 来, 从 而 极 大 的 减 少 了 软 件 开 发 的 工 作 量,
缩 短 开 发 周 期, 提 高 了 效 率 和 软 件 的 可 靠 性。 本 文 总 结
的 笔 者 从 事 软 件 开 发 的 一 些 经 验 心 得 希 望 对 从 事ODBC 开
发 的 工 作 者 有 所 帮 助。
#9
学习
#10
我做了,还是不能解决问题。
#11
如果你不用动态打开任意数据表,在建立CRecordSet派生类是可以对多个表的任意字段进行绑定,在打开时将字段名在SQL里写清楚就行了。
如果不绑定字段,好象是会出错的。
如果不绑定字段,好象是会出错的。
#12
是什么数据库啊?
#13
好了,给分了,不过我了ADO
#1
请大将帮帮忙……
up者都有分
up者都有分
#2
odbc 我不是很清楚
ado可以一次打开一个库,随便怎么操作
我估计odbc也是一样的
ado可以一次打开一个库,随便怎么操作
我估计odbc也是一样的
#3
应该是的吧
用REQUERY再试试看吧
用REQUERY再试试看吧
#4
如果用CDatabase和CRecordset直接操作数据库,SQL语句绝对是个很有用的工具。下面是个例子:
bool SomeFunc()
{
CDatabase db;
try{
db.Open("DSN=testdb;UID=sa;PWD="); //Open Database
}catch(CDBException * e)
{
e->Delete();
TRACE("Error Opening database\n");
return false;
}
CRecordset rec(&db);
try{
rec.Open(AFX_DB_USE_DEFAULT_TYPE, "select * from testtable"); //Open Rec
if(rec.IsBOF()) return false; //Return if empty
TRACE("Col1:\n----------\n");
CDBVariant value;
while(rec.IsEOF()) //Enumerate all values
{
rec.GetFieldValue("Col1",&value);
TRACE("%d\n",value.m_iVal) //if Col1 is short type value
rec.MoveNext();
}
rec.Close();
}catch(CDBException * e)
{
e->Delete();
rec.Close();
return false;
}
return true;
}
对其他表或视图可以类似处理。如果插入记录可以直接用db.ExecuteSQL。
bool SomeFunc()
{
CDatabase db;
try{
db.Open("DSN=testdb;UID=sa;PWD="); //Open Database
}catch(CDBException * e)
{
e->Delete();
TRACE("Error Opening database\n");
return false;
}
CRecordset rec(&db);
try{
rec.Open(AFX_DB_USE_DEFAULT_TYPE, "select * from testtable"); //Open Rec
if(rec.IsBOF()) return false; //Return if empty
TRACE("Col1:\n----------\n");
CDBVariant value;
while(rec.IsEOF()) //Enumerate all values
{
rec.GetFieldValue("Col1",&value);
TRACE("%d\n",value.m_iVal) //if Col1 is short type value
rec.MoveNext();
}
rec.Close();
}catch(CDBException * e)
{
e->Delete();
rec.Close();
return false;
}
return true;
}
对其他表或视图可以类似处理。如果插入记录可以直接用db.ExecuteSQL。
#5
EagleCK(),我按照您的方法……出现这样的提示,为什么?
在调用 SQLFetchScroll/SQLExtendedFetch 之前列没有绑定数据列
State:SL009,Native:0,Origin:[Microsoft][ODBC 游标库]
在调用 SQLFetchScroll/SQLExtendedFetch 之前列没有绑定数据列
State:SL009,Native:0,Origin:[Microsoft][ODBC 游标库]
#6
打一数据库后,用多个CRecordset对象就可以打开多个表呀。
#7
luckyegg(幸运蛋)
但是我在执行p_Set.Open(CRecordset::snapshot,"SELECT * FROM table");没有问题,
而在
while(!p_Set.IsEOF())
{
p_Set.GetFieldValue("id_number",varName);
Temp = varName.m_pstring->GetBuffer(100);
varName.m_pstring->ReleaseBuffer();
p_Set.MoveNext();
}
时就会提示“非法的描述器索引”或者“无效的描述器索引”
但是我在执行p_Set.Open(CRecordset::snapshot,"SELECT * FROM table");没有问题,
而在
while(!p_Set.IsEOF())
{
p_Set.GetFieldValue("id_number",varName);
Temp = varName.m_pstring->GetBuffer(100);
varName.m_pstring->ReleaseBuffer();
p_Set.MoveNext();
}
时就会提示“非法的描述器索引”或者“无效的描述器索引”
#8
Visual C++ 中 的ODBC 编 程
一 . 概 述
---- ODBC 是 一 种 使 用SQL 的 程 序 设 计 接 口。 使 用ODBC 让 应 用
程 序 的 编 写 者 避 免 了 与 数 据 源 相 联 的 复 杂 性。 这 项 技
术 目 前 已 经 得 到 了 大 多 数DBMS 厂 商 们 的 广 泛 支 持。
---- Microsoft Developer Studio 为 大 多 数 标 准 的 数 据 库 格 式 提
供 了32 位ODBC 驱 动 器。 这 些 标 准 数 据 格 式 包 括 有:
SQL Server、Access、Paradox、dBase、FoxPro、Excel、Oracle 以 及
Microsoft Text。 如 果 用 户 希 望 使 用 其 他 数 据 格 式, 用 户 需
要 相 应 的ODBC 驱 动 器 及DBMS。
---- 用 户 使 用 自 己 的DBMS 数 据 库 管 理 功 能 生 成 新 的 数 据
库 模 式 后, 就 可 以 使 用ODBC 来 登 录 数 据 源。 对 用 户 的 应
用 程 序 来 说, 只 要 安 装 有 驱 动 程 序, 就 能 注 册 很 多 不 同
的 数 据 库。 登 录 数 据 库 的 具 体 操 作 参 见 有 关ODBC 的 联 机
帮 助。
二 .MFC 提 供 的ODBC 数 据 库 类
---- Visual C++ 的MFC 基 类 库 定 义 了 几 个 数 据 库 类。 在 利
用ODBC 编 程 时, 经 常 要 使 用 到 CDatabase( 数 据 库 类),
CRecordSet( 记 录 集 类) 和CRecordView( 可 视 记 录 集 类)。 其 中:
---- CDatabase 类 对 象 提 供 了 对 数 据 源 的 连 接, 通 过 它 你
可 以 对 数 据 源 进 行 操 作。
---- CRecordSet 类 对 象 提 供 了 从 数 据 源 中 提 取 出 的 记 录 集。
CRecordSet 对 象 通 常 用 于 两 种 形 式: 动 态 行 集(dynasets) 和
快 照 集(snapshots)。 动 态 行 集 能 保 持 与 其 他 用 户 所 做 的
更 改 保 持 同 步。 快 照 集 则 是 数 据 的 一 个 静 态 视 图。 每 一
种 形 式 在 记 录 集 被 打 开 时 都 提 供 一 组 记 录, 所 不 同 的 是,
当 你 在 一 个 动 态 行 集 里 滚 动 到 一 条 记 录 时, 由 其 他 用
户 或 是 你 应 用 程 序 中 的 其 他 记 录 集 对 该 记 录 所 做 的 更
改 会 相 应 地 显 示 出 来。
---- CRecordView 类 对 象 能 以 控 制 的 形 式 显 示 数 据 库 记 录。
这 个 视 图 是 直 接 连 到 一 个CRecordSet 对 象 的 表 视 图。
三 . 应 用ODBC 编 程
---- 应 用Visual C++ 的AppWizard 可 以 自 动 生 成 一 个ODBC 应 用 程
序 框 架。 方 法 是: 打 开File 菜 单 的New 选 项, 选 取Projects,
填 入 工 程 名, 选 择MFC AppWizard (exe), 然 后 按AppWizard 的 提
示 进 行 操 作。 当AppWizard 询 问 是 否 包 含 数 据 库 支 持 时, 如
果 你 想 读 写 数 据 库, 那 么 选 定Database view with file support;
而 如 果 你 想 访 问 数 据 库 的 信 息 而 不 想 回 写 所 做 的 改 变,
那 么 选 定Database view without file support 选 项 就 比 较 合 适 了。
选 择 了 数 据 库 支 持 之 后Database Source 按 钮 会 激 活, 选 中
它 去 调 用Data Options 对 话 框。 在Database Options 对 话 框 中 会
显 示 已 向ODBC 注 册 的 数 据 库 资 源, 选 定 你 所 要 操 作 的 数
据 库, 如:Super_ES, 单 击OK 后 会 出 现Select Database Tables 对
话 框, 其 中 列 举 了 你 所 选 中 的 数 据 库 中 包 含 的 全 部 表,
选 择 你 希 望 操 作 的 表 后, 单 击OK。 在 选 定 了 数 据 库 和 数
据 表 之 后, 你 可 以 按 照 惯 例 继 续 进 行AppWizard 操 作。
---- 特 别 需 要 指 出 的 是: 在 生 成 的 应 用 程 序 框 架View 类
( 如:CSuper_ESView) 中 包 含 一 个 指 向CSuper_ESSet 对 象 的 指
针m_pSet, 该 指 针 由AppWizard 建 立, 目 的 是 在 视 表 单 和 记 录
集 之 间 建 立 联 系, 使 得 记 录 集 中 的 查 询 结 果 能 够 很 容
易 地 在 视 表 单 上 显 示 出 来。 有 关m_pSet 的 详 细 用 法 可 以
参 见Visual C++ Online Book。
---- 程 序 与 数 据 语 言 建 立 联 系, 使 用CDatebase::OpenEx() 或
CDatabase::Open() 函 数 来 进 行 初 始 化。 数 据 库 对 象 必 须 在
你 使 用 它 构 造 一 个 记 录 集 对 象 之 前 被 初 始 化。
---- 下 面 举 例 说 明 在Visual C++ 环 境 中ODBC 的 编 程 技 巧:
---- 1 . 查 询 记 录
---- 查 询 记 录 使 用CRecordSet::Open() 和CRecordSet::Requery() 成
员 函 数。 在 使 用CRecordSet 类 对 象 之 前, 必 须 使 用
CRecordSet::Open() 函 数 来 获 得 有 效 的 记 录 集。 一 旦 已 经 使
用 过CRecordSet::Open() 函 数, 再 次 查 询 时 就 可 以 应 用
CRecordSet::Requery() 函 数。 在 调 用CRecordSet::Open() 函 数 时,
如 果 已 经 将 一 个 已 经 打 开 的CDatabase 对 象 指 针 传 给
CRecordSet 类 对 象 的m_pDatabase 成 员 变 量, 则 使 用 该 数 据 库
对 象 建 立ODBC 连 接; 否 则 如 果m_pDatabase 为 空 指 针, 就 新 建
一 个CDatabase 类 对 象 并 使 其 与 缺 省 的 数 据 源 相 连, 然 后
进 行CRecordSet 类 对 象 的 初 始 化。 缺 省 数 据 源 由
GetDefaultConnect() 函 数 获 得。 你 也 可 以 提 供 你 所 需 要 的SQL
语 句, 并 以 它 来 调 用CRecordSet::Open() 函 数, 例 如:
---- Super_ESSet.Open(AFX_DATABASE_USE_DEFAULT,strSQL);
---- 如 果 没 有 指 定 参 数, 程 序 则 使 用 缺 省 的SQL 语 句, 即
对 在GetDefaultSQL() 函 数 中 指 定 的SQL 语 句 进 行 操 作:
CString CSuper_ESSet::GetDefaultSQL()
{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 对 象
---- 7 .SQL 语 句 的 直 接 执 行
---- 虽 然 通 过CRecordSet 类, 我 们 可 以 完 成 大 多 数 的 查 询
操 作, 而 且 在CRecordSet::Open() 函 数 中 也 可 以 提 供SQL 语 句,
但 是 有 的 时 候 我 们 还 想 进 行 一 些 其 他 操 作, 例 如 建 立 新
表, 删 除 表, 建 立 新 的 字 段 等 等, 这 时 就 需 要 使 用 到
CDatabase 类 的 直 接 执 行SQL 语 句 的 机 制。 通 过 调 用
CDatabase::ExecuteSQL() 函 数 来 完 成SQL 语 句 的 直 接 执 行:
BOOL CDB::ExecuteSQLAndReportFailure(const CString& strSQL)
{
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;
}
}
四 . 总 结
---- Visual C++ 中 的ODBC 类 库 可 以 帮 助 程 序 员 完 成 绝 大 多
数 的 数 据 库 操 作。 利 用ODBC 技 术 使 得 程 序 员 从 具 体 的
DBMS 中 解 脱 出 来, 从 而 极 大 的 减 少 了 软 件 开 发 的 工 作 量,
缩 短 开 发 周 期, 提 高 了 效 率 和 软 件 的 可 靠 性。 本 文 总 结
的 笔 者 从 事 软 件 开 发 的 一 些 经 验 心 得 希 望 对 从 事ODBC 开
发 的 工 作 者 有 所 帮 助。
一 . 概 述
---- ODBC 是 一 种 使 用SQL 的 程 序 设 计 接 口。 使 用ODBC 让 应 用
程 序 的 编 写 者 避 免 了 与 数 据 源 相 联 的 复 杂 性。 这 项 技
术 目 前 已 经 得 到 了 大 多 数DBMS 厂 商 们 的 广 泛 支 持。
---- Microsoft Developer Studio 为 大 多 数 标 准 的 数 据 库 格 式 提
供 了32 位ODBC 驱 动 器。 这 些 标 准 数 据 格 式 包 括 有:
SQL Server、Access、Paradox、dBase、FoxPro、Excel、Oracle 以 及
Microsoft Text。 如 果 用 户 希 望 使 用 其 他 数 据 格 式, 用 户 需
要 相 应 的ODBC 驱 动 器 及DBMS。
---- 用 户 使 用 自 己 的DBMS 数 据 库 管 理 功 能 生 成 新 的 数 据
库 模 式 后, 就 可 以 使 用ODBC 来 登 录 数 据 源。 对 用 户 的 应
用 程 序 来 说, 只 要 安 装 有 驱 动 程 序, 就 能 注 册 很 多 不 同
的 数 据 库。 登 录 数 据 库 的 具 体 操 作 参 见 有 关ODBC 的 联 机
帮 助。
二 .MFC 提 供 的ODBC 数 据 库 类
---- Visual C++ 的MFC 基 类 库 定 义 了 几 个 数 据 库 类。 在 利
用ODBC 编 程 时, 经 常 要 使 用 到 CDatabase( 数 据 库 类),
CRecordSet( 记 录 集 类) 和CRecordView( 可 视 记 录 集 类)。 其 中:
---- CDatabase 类 对 象 提 供 了 对 数 据 源 的 连 接, 通 过 它 你
可 以 对 数 据 源 进 行 操 作。
---- CRecordSet 类 对 象 提 供 了 从 数 据 源 中 提 取 出 的 记 录 集。
CRecordSet 对 象 通 常 用 于 两 种 形 式: 动 态 行 集(dynasets) 和
快 照 集(snapshots)。 动 态 行 集 能 保 持 与 其 他 用 户 所 做 的
更 改 保 持 同 步。 快 照 集 则 是 数 据 的 一 个 静 态 视 图。 每 一
种 形 式 在 记 录 集 被 打 开 时 都 提 供 一 组 记 录, 所 不 同 的 是,
当 你 在 一 个 动 态 行 集 里 滚 动 到 一 条 记 录 时, 由 其 他 用
户 或 是 你 应 用 程 序 中 的 其 他 记 录 集 对 该 记 录 所 做 的 更
改 会 相 应 地 显 示 出 来。
---- CRecordView 类 对 象 能 以 控 制 的 形 式 显 示 数 据 库 记 录。
这 个 视 图 是 直 接 连 到 一 个CRecordSet 对 象 的 表 视 图。
三 . 应 用ODBC 编 程
---- 应 用Visual C++ 的AppWizard 可 以 自 动 生 成 一 个ODBC 应 用 程
序 框 架。 方 法 是: 打 开File 菜 单 的New 选 项, 选 取Projects,
填 入 工 程 名, 选 择MFC AppWizard (exe), 然 后 按AppWizard 的 提
示 进 行 操 作。 当AppWizard 询 问 是 否 包 含 数 据 库 支 持 时, 如
果 你 想 读 写 数 据 库, 那 么 选 定Database view with file support;
而 如 果 你 想 访 问 数 据 库 的 信 息 而 不 想 回 写 所 做 的 改 变,
那 么 选 定Database view without file support 选 项 就 比 较 合 适 了。
选 择 了 数 据 库 支 持 之 后Database Source 按 钮 会 激 活, 选 中
它 去 调 用Data Options 对 话 框。 在Database Options 对 话 框 中 会
显 示 已 向ODBC 注 册 的 数 据 库 资 源, 选 定 你 所 要 操 作 的 数
据 库, 如:Super_ES, 单 击OK 后 会 出 现Select Database Tables 对
话 框, 其 中 列 举 了 你 所 选 中 的 数 据 库 中 包 含 的 全 部 表,
选 择 你 希 望 操 作 的 表 后, 单 击OK。 在 选 定 了 数 据 库 和 数
据 表 之 后, 你 可 以 按 照 惯 例 继 续 进 行AppWizard 操 作。
---- 特 别 需 要 指 出 的 是: 在 生 成 的 应 用 程 序 框 架View 类
( 如:CSuper_ESView) 中 包 含 一 个 指 向CSuper_ESSet 对 象 的 指
针m_pSet, 该 指 针 由AppWizard 建 立, 目 的 是 在 视 表 单 和 记 录
集 之 间 建 立 联 系, 使 得 记 录 集 中 的 查 询 结 果 能 够 很 容
易 地 在 视 表 单 上 显 示 出 来。 有 关m_pSet 的 详 细 用 法 可 以
参 见Visual C++ Online Book。
---- 程 序 与 数 据 语 言 建 立 联 系, 使 用CDatebase::OpenEx() 或
CDatabase::Open() 函 数 来 进 行 初 始 化。 数 据 库 对 象 必 须 在
你 使 用 它 构 造 一 个 记 录 集 对 象 之 前 被 初 始 化。
---- 下 面 举 例 说 明 在Visual C++ 环 境 中ODBC 的 编 程 技 巧:
---- 1 . 查 询 记 录
---- 查 询 记 录 使 用CRecordSet::Open() 和CRecordSet::Requery() 成
员 函 数。 在 使 用CRecordSet 类 对 象 之 前, 必 须 使 用
CRecordSet::Open() 函 数 来 获 得 有 效 的 记 录 集。 一 旦 已 经 使
用 过CRecordSet::Open() 函 数, 再 次 查 询 时 就 可 以 应 用
CRecordSet::Requery() 函 数。 在 调 用CRecordSet::Open() 函 数 时,
如 果 已 经 将 一 个 已 经 打 开 的CDatabase 对 象 指 针 传 给
CRecordSet 类 对 象 的m_pDatabase 成 员 变 量, 则 使 用 该 数 据 库
对 象 建 立ODBC 连 接; 否 则 如 果m_pDatabase 为 空 指 针, 就 新 建
一 个CDatabase 类 对 象 并 使 其 与 缺 省 的 数 据 源 相 连, 然 后
进 行CRecordSet 类 对 象 的 初 始 化。 缺 省 数 据 源 由
GetDefaultConnect() 函 数 获 得。 你 也 可 以 提 供 你 所 需 要 的SQL
语 句, 并 以 它 来 调 用CRecordSet::Open() 函 数, 例 如:
---- Super_ESSet.Open(AFX_DATABASE_USE_DEFAULT,strSQL);
---- 如 果 没 有 指 定 参 数, 程 序 则 使 用 缺 省 的SQL 语 句, 即
对 在GetDefaultSQL() 函 数 中 指 定 的SQL 语 句 进 行 操 作:
CString CSuper_ESSet::GetDefaultSQL()
{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 对 象
---- 7 .SQL 语 句 的 直 接 执 行
---- 虽 然 通 过CRecordSet 类, 我 们 可 以 完 成 大 多 数 的 查 询
操 作, 而 且 在CRecordSet::Open() 函 数 中 也 可 以 提 供SQL 语 句,
但 是 有 的 时 候 我 们 还 想 进 行 一 些 其 他 操 作, 例 如 建 立 新
表, 删 除 表, 建 立 新 的 字 段 等 等, 这 时 就 需 要 使 用 到
CDatabase 类 的 直 接 执 行SQL 语 句 的 机 制。 通 过 调 用
CDatabase::ExecuteSQL() 函 数 来 完 成SQL 语 句 的 直 接 执 行:
BOOL CDB::ExecuteSQLAndReportFailure(const CString& strSQL)
{
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;
}
}
四 . 总 结
---- Visual C++ 中 的ODBC 类 库 可 以 帮 助 程 序 员 完 成 绝 大 多
数 的 数 据 库 操 作。 利 用ODBC 技 术 使 得 程 序 员 从 具 体 的
DBMS 中 解 脱 出 来, 从 而 极 大 的 减 少 了 软 件 开 发 的 工 作 量,
缩 短 开 发 周 期, 提 高 了 效 率 和 软 件 的 可 靠 性。 本 文 总 结
的 笔 者 从 事 软 件 开 发 的 一 些 经 验 心 得 希 望 对 从 事ODBC 开
发 的 工 作 者 有 所 帮 助。
#9
学习
#10
我做了,还是不能解决问题。
#11
如果你不用动态打开任意数据表,在建立CRecordSet派生类是可以对多个表的任意字段进行绑定,在打开时将字段名在SQL里写清楚就行了。
如果不绑定字段,好象是会出错的。
如果不绑定字段,好象是会出错的。
#12
是什么数据库啊?
#13
好了,给分了,不过我了ADO