ADOSTLCOMVisual Studio 6Windows 2000Visual C++ 6.0Windows XPMFCIntermediateDevVisual StudioWindowsC++
通过 ADO 更新和添加数据库记录






4.16/5 (13投票s)
2007年1月31日
8分钟阅读

71858

2259
一篇关于通过VC++(MFC)使用OLE DB和ODBC API的文章。并附带一些比较。
引言
这篇文章将带您进入数据库的神秘世界,探索OLE DB和ODBC的一些基本概念。我为什么写这篇文章?…… 仅仅是为了与程序员分享知识,同时,在我开发第一个集成数据库的C++应用程序时,我遇到了许多与数据库连接及其工作相关的难题。因此,我希望阅读完本文后,程序员能够对C++中的数据库风险有一个初步的认识和概念。您将在这里找到OLE DB和ODBC两个API的介绍以及一些代码片段。
背景
本文不需要任何特殊的背景知识,您只需要了解数据库概念,并熟悉VC++和MFC环境。如果您能进一步深入学习它们会更好。
https://codeproject.org.cn/database/connectionstrings.asp
https://codeproject.org.cn/database/oledbconsumer1.asp
使用代码
当您通读全文后,会发现它非常精妙且概念性强。我希望那时您能轻松理解代码片段及其用法。为了方便您,我附上了一些可用于操作数据库的代码和算法,以及本文的PPT格式。您可以下载并尽情享用。
VC++中访问数据库的技术
VC++在您的应用程序中使用和访问数据库提供了以下技术:1) 数据访问对象 (DAO)
2) 开放数据库连接器 (ODBC)
3) OLE(对象链接与嵌入)数据库
4) ActiveX 数据对象 (ADO)
我们将详细介绍ADO,并讨论一些ODBC和OLE DB。
OLE DB & ODBC
OLE DB 和 ODBC 是为了提供对广泛数据源的访问而设计的API。ODBC
主要旨在跨平台环境中提供对SQL数据的访问。OLE DB
包含了ODBC
中定义的SQL功能,但也定义了适用于访问非SQL数据的接口。ODBC
是为了访问关系数据库而创建的。OLE DB
是为关系型和非关系型信息源设计的,例如Web的文本和图形数据。任何可能包含数据的内容都可以通过
OLE DB
技术进行访问。什么是ADO?
ADO
被设计为OLE DB
之上的另一层,专门用于数据库访问。Web浏览器用户可以在客户端缓存整套数据记录。
ADO
控件随Microsoft的Internet Explorer Web浏览器(4.0及以上版本)分发。ADO对象
1-基本对象包括:2-Connection
3-Error
4-Command
5-Parameter
6-Recordset
7-Field
连接对象
->用于建立和维护与数据库的连接。->建立连接
->在打开连接之前,使用数据库位置、用户ID和密码等连接信息配置对象。
->调用其Open方法打开连接。
->调用其Close方法关闭连接。
->通过Connection对象控制所有高级连接功能。
->这包括通过Connection对象的BeginTrans、CommitTrans和RollbackTrans方法进行所有事务控制。
Error Object (错误对象)
->每当发生数据库错误时,数据库的错误信息将被放入ADO
Error对象中。->错误对象中的信息是数据库的错误信息,而不是
ADO
的错误信息。命令对象
->用于在数据库中执行命令。->此对象可用于运行SQL语句或调用存储过程(存储在数据库中的SQL函数)。
参数对象
. ->用于传递变量以及调用存储过程或参数化查询。->附加到Command对象以供调用命令使用。
Recordset Object (记录集对象)
->此对象包含数据库中的一组记录。->记录集是发送到数据库的命令的结果,该命令返回一组记录。
Field Object (字段对象)
它代表Recordset中的单个列。->Field对象始终包含Variant数据值。->使用
ADO
对象的程序员必须将Variant的值转换为所需的数据类型,并在更新值时将其转换回Variant。使用ADO ActiveX控件
->在Visual C++应用程序中有两种不同的方法来使用ADO
控件。->通过使用ActiveX控件将
ADO
集成到应用程序中的简单方法是:->将ADO ActiveX控件添加到项目中。
ADO
控件指定为控件的数据源。ADO
控件数据库应用程序。ADO
应用程序时涉及大量的非必要开销。对于您想要提取的每个SQL查询或表,都需要添加一个单独的ADO
控件。每个ADO控件都会建立一个单独的数据库连接,这可能会给连接数有限制的数据库带来问题。并非所有数据绑定控件都支持
ADO
。导入ADO DLL
->MFC类层次结构中没有可以直接用于ADO
的类。->Microsoft提供了其他方法,通过使用一个新的C++预编译器指令#import来为
ADO
中的每个对象创建和使用类。这个
#import
指令告诉Visual C++编译器导入指定的DLL,创建自动包含在项目中的头文件。这些头文件的文件扩展名是.TLH 和 .TLI
。这两个文件包含DLL中可用于代码的每个对象的类定义。#import指令消除了在项目中包含DLL的.LIB文件的需要。通过在定义数据库对象的头文件开头放置以下代码来导入ADO
DLL:#define INITGUID #import "C:\Program Files\CommonFiles\System\ADO\msado15.dll" rename_namespace("ADOCG") rename("EOF", "EndOfFile") using namespace ADOCG; #include "icrsint.h"
连接数据库
COM
是ActiveX控件和OLE的基础“对象模型”。在使用任何ADO
对象之前,必须初始化应用程序的COM环境,以调用ActiveX对象:::CoInitialize(NULL);在完成所有
ADO
活动后,必须通过调用CoUninitialize函数来关闭COM环境,如下所示:CoUninitialize();
此函数清理COM环境并为应用程序关闭做准备。
创建数据库连接
Declare a Connection object pointer, _ConnectionPtr
_ConnectionPtr pConn; pConn.CreateInstance(__uuidof(Connection));
pConn->Open(L"Provider=MSDASQL.1;DataSource=TYVCDB", L"", L"",adOpenUnspecified);
执行命令并检索数据
声明一个Command对象指针,_CommandPtr,然后使用Command对象的UUID创建一个实例,如下所示:_CommandPtr pCmd; pCmd.CreateInstance(__uuidof(Command)); pCmd->ActiveConnection = pConn;接下来,通过设置Command对象的CommandText属性来指定要执行的SQL命令,如下所示:
pCmd->CommandText = "Select * from Addresses";
此时,有两种选择可以执行此命令并检索记录。1) _RecordsetPtr pRs; pRs = pCmd->Execute(); 2) _RecordsetPtr pRs; pRs.CreateInstance(__uuidof(Recordset)); pRs->PutRefSource(pCmd); // Create the variant NULL _variant_t vNull; vNull.vt = VT_ERROR; vNull.scode = DISP_E_PARAMNOTFOUND; // Open the recordset pRs->Open(vNull, vNull, adOpenDynamic,adLockOptimistic, adCmdUnknown);
另一种方法可以用很少的代码完成前面所有的任务:
完全跳过Command和Connection对象的使用,将所有必要的连接信息放在Recordset的Open函数中。_RecordsetPtr pRs;
pRs.CreateInstance(__uuidof(Recordset));
pRs->Open(_T("Provider=MSDASQL.1;Data Source=TYVCDB"), _T("select * from Addresses"),
adOpenDynamic, adLockOptimistic, adCmdUnknown);
导航Recordset
需要导航记录集的函数:MoveFirst, MoveLast, MovePrevious, 和 MoveNext
Recordset对象还有两个属性:BOF 和 EOF。
访问字段值
从ADO
Recordset的字段中检索到的所有数据元素都是variant值。它们需要被转换为所需使用的数据类型。
有两种方法可以做到这一点。
1)Retreive values into a variant and then convert them
_variant_t vName;
CString strName;
vName = pRs-> GetCollect(_variant_t("Name"));
vName.ChangeType(VT_BSTR); strName = vName.bstrVal;
2) Microsoft创建了一系列宏来执行转换并维护记录集中的变量。为此,请定义一个新类作为记录集的接口。此类将继承自CADORecordBinding类,该类定义在icrsint.h头文件中。class CCustomRs : public CADORecordBinding { BEGIN_ADO_BINDING(CCustomRs) ADO_FIXED_LENGTH_ENTRY (1, adInteger, m_ID, IDStatus, FALSE) ADO_VARIABLE_LENGTH_ENTRY2(2, adVarChar, m_Name, sizeof(m_Name), NameStatus, TRUE) ADO_FIXED_LENGTH_ENTRY(3, adDate, m_Birthdate, BirthdateStatus, TRUE) END_ADO_BINDING() public: LONG m_ID; ULONG IDStatus; CHAR m_Name[20]; ULONG NameStatus; DATE m_Birthdate; ULONG BirthdateStatus; };声明该类的一个变量。接下来,创建IADORecordBinding接口的指针:CCustomRs m_RecSet; IADORecordBinding *Rs = NULL; IADORecordBinding接口将Recordset对象的字段绑定到C/C++变量。每当绑定的Recordset的当前行发生变化时,所有绑定的字段都会被复制到变量中。
IADORecordBinding接口方法
1)BindToRecordset2)AddNew
3)Update
一旦记录集被检索,就检索IADORecordBinding接口的指针,并将自定义记录集类绑定到Recordset对象,如下面的代码所示:
if (FAILED(pRs->QueryInterface(__uuidof(IADORecordBinding), (LPVOID *)&Rs))) _com_issue_error(E_NOINTERFACE); Rs->BindToRecordset(&m_RecSet);
宏
BEGIN_ADO_BINDING
宏设置了与其余宏一起创建的结构定义。宏集由
END_ADO_BINDING
宏关闭。ADO_FIXED_LENGTH_ENTRY
它用于大小固定的任何数据库字段。
ADO_NUMERIC_ENTRY Macros
宏只用于数字字段。ADO_VARIABLE_LENGTH_ENTRY Macros
使用此系列宏处理长度可能变化的数据库字段。更新记录
如果您手动检索每个字段并将其从variant转换,则需要更新已更改的每个单独字段。_variant_t vName, vValue; vName.SetString("Name"); vValue.SetString("Saqib"); pRs->Update(vName, vValue);
如果您创建了记录类并将其绑定到记录集,更新记录会稍微简单一些。Rs->Update(&m_RecSet);添加和删除
要删除当前记录,请调用Recordset对象的Delete方法。pRs->Delete(adAffectCurrent); pRs->MovePrevious();
添加新记录
您不能直接开始向字段输入数据值。为了让用户立即输入新记录的各种数据元素,请将记录类中的值清空,并将Recordset类变量作为唯一参数传递给AddNew方法。通过记录绑定接口指针调用它,如下例所示:CString strBlank = " ";
COleDateTime dtBlank;
m_RecSet.m_ID = 0; strcpy(m_RecSet.m_Name, (LPCTSTR)strBlank);
m_RecSet.m_dtBirthdate = (DATE)dtBlank;
Rs->AddNew(&m_RecSet);
关闭Recordset和Connection对象
完成记录集工作后,调用pRs->Close();
。完成应用程序所有数据库交互后,通过调用Connection对象的Close方法关闭数据库连接:pConn->Close();
关注点
始终尝试为内置的MFC、STL、ATL类编写包装类,以便以最佳方式利用它们。本文在我的朋友GOLD
的帮助下完成……我从他那里学到了帮助他人变得更好。历史
请及时更新您在这里所做的任何更改或改进。如果您有任何疑问,请告知我。谢谢。