创建 OLE DB 数据提供程序






3.45/5 (13投票s)
2002年1月13日
9分钟阅读

130036

3444
本文介绍如何创建 OLE DB 数据提供程序,该程序包装 C 结构和 C++ 类,其中包含要通过 SQL 查询访问的数据。
引言
OLE DB 是 Microsoft 面向各种数据源的系统级编程接口。OLE DB 指定了一组 Microsoft 组件对象模型 (COM) 接口,这些接口封装了各种数据库管理系统服务。以下示例演示了如何创建 OLE DB 数据提供程序,该程序包装 C 结构和 C++ 类,其中包含要通过 SQL 查询访问的数据。此数据提供程序支持数据的读取和写入,但不支持事务。它包含一个简单的 SQL 解析器,足以允许 Visual Basic 数据环境设计器访问元数据。该示例演示了如何使用 ADO 创建 C++ OLE DB 数据使用者。数据使用者演示了如何使用 Microsoft 提供的 OLE DB 数据服务 MsDataShape。它还演示了如何使用 ADO 事件在数据表更新时接收回调。
OLE DB
OLE DB 指定了一组 COM 接口,这些接口封装了各种数据库管理系统服务。Microsoft 提供了一个最小实现模板,以确保所有功能正常运行。实际上,使用 Visual C++,您可以生成一个简单的数据提供程序和使用者来共享数据。本文的要点在于展示简单的提供程序在哪些方面显得过于简单。您可以参考 MSDN 库中的文章“OLE DB/ADO:让通用数据访问成为现实”,了解 OLE DB 的概述。
OLE DB 数据提供程序
数据提供程序由四个组件组成:数据源、会话、命令和行集。
提供程序拥有一个包含硬编码数据的行集实例。这可以轻松转换为从用户指定的文件获取数据。Star Rowset 说明了根据输入参数计算数据的示例。提供程序包含一个简单的 SQL 解析器。下一节将解释为其他项目使用此代码需要更改哪些内容。
数据源 – 请参阅 MySensorDS.h
数据源是您的 DLL 注册为 OLE DB 提供程序的 COM 对象。这里唯一进行的修改是使 dbprop INIT_DATASOURCE 可写,并在数据库打开后捕获它。
会话 – 请参阅 MySensorSess.h 和 .cpp
会话是控制数据事务(例如开始、提交和回滚)的 COM 对象。它还使用 SCHEMA_MAP 提供数据库的元数据。这些实现起来相当直接。但是,请确保提供了可选字段:DBCOLUMN_BASECOLUMNNAME、DBCOLUMN_BASETABLENAME 和 DBCOLUMN_KEYCOLUMN(参见 IColumnsRowsetImpl.h)。
命令 – 请参阅 MySensorCmd.h 和 .cpp
命令是接收 SQL 的 COM 对象。它需要解析 SQL 并将行集返回给使用者。添加了多个 dbprops 以声明数据库支持更新和回调事件。Execute() 例程会解析 SQL 命令。它假定该命令是针对单个表的。它在硬编码数据中找到表的名称,并指示该表返回所选行的副本。GetColumnInfo() 例程将解析单个表名的 SQL 命令,并返回有关该表的元数据。
行集 – 请参阅 MySensorRS.h 和 .cpp
行集是包含数据的 COM 对象。硬编码数据位于行集的 STL 映射中。Command::Exexcute() 将返回这些行集之一的副本。行集包含指向实际数据的对象。如果它是一个 C++ 类,那么您可以使用 PROVIDER_COLUMN_MAP 来描述类的成员。如果它是一个 C 结构,那么您必须用一个类来包装它,并让包装器实现 GetColumnInfo() 的两个版本。行集必须实现 Execute() 例程。添加了一个模板实现 IMyRowsetUpdateImpl 来简化 Execute() 例程的编码。注意:Star Rowset 不调用 MyExecute(),而是根据输入参数计算数据。
SQL 解析器 – 请参阅 SqlParser.cpp, SqlCollections.cpp
SQL 解析器支持 SELECT、UPDATE、INSERT、DELETE 和简单的 where 子句。它为指定的每个关键字和值创建一个 CString 的链表。它验证表名和列名。添加了一个辅助函数 FindColumnOperator(),该函数返回指定列的操作符和值。这允许数据库编写者支持需要在返回数据之前计算数据查询。请参阅 Star Rowset 示例。解析器包含一个 Print 函数来帮助调试提供程序。
数据 – 请参阅 MyData.h 和 .cpp
OLE DB 系统提供的数据以行集的形式存在。MyData 是一个全局对象,它提供一个以这些行表的表名作为键的映射。这使得系统中的任何地方都可以轻松访问已实现的表。映射中的每个表至少必须包含一行数据。这将允许在运行时即使“实际”值将被计算,也能访问该表的元数据。MyData 还使用表名和列名加载 SqlParser。一个改进之处是更改 SqlParser,使其从 GetColumnInfo() 获取此信息,而不是单独存储。
另一个 OLE DB 项目
上述代码的很多部分可以直接用于任何 OLE DB 提供程序。新项目需要将类名从 MyXXX 更改为 <新名称>XXX。MyDataSource 中的 GUID 需要更改。MySensorRowset.h 中的大部分代码需要更改以使用新的数据类。MySensorRowset.cpp 中的代码也需要支持新的类。请注意,如果数据不是计算得出的,则 Execute() 例程可以简单地在 MyData::map 中找到正确的表并调用 MyExecute()。MyData.cpp 中存储的数据需要更改。.rc 文件必须包含一个指向 .rgs 文件的注册表项。数据源通过 DECLARE_REGISTRY_RESOURCEID 使用此项。.rc 文件和 resource.h 文件应包含 IDS_XXX 值。将这些复制到您项目的相应文件中。
OLE DB 数据使用者 – 请参阅 SensorInterfDlg.h 和 .cpp
Microsoft 已经做了大量工作,试图通过 ADO (ActiveX Data Objects) 使数据库访问变得简单且通用。这在 Visual Basic 中尤其有用,因为 OLE DB 的 COM 对象使用起来很麻烦。然而,它也简化了 C++ 中的事情。ADO 具有连接的概念,并声明了智能指针 _ConnectionPtr。当用户打开连接时,他们会指定数据库名称,可选地包括用户名、授权和数据库位置。连接将打开数据源并在数据提供程序中启动一个会话。ADO 还具有 Recordset 的概念,并声明了智能指针 _RecordsetPtr。Recordset 与数据提供程序中的 Rowset 非常相似。用户可以通过指定 SQL 语句和连接来打开 Recordset。SQL 语句将传递给 Command 对象,该对象会将数据返回给 Recordset。
SQL – 支持的子集
当前数据提供程序仅支持完整 SQL 语言的子集:SELECT、UPDATE、INSERT、DELETE 和简单的 where 子句。where 子句的值应在 SQL 文本中,而不是作为单独的 Command 参数指定。解析器不实现 where 子句。但是,某些表可能已实现了特定的查询。使用者需要与数据提供程序核实支持哪些 where 子句。Star Rowset 是此类实现的示例。
MsDataShape – 支持多表
SQL 解析器仅支持单个表的查询。但是,可以通过 Microsoft 提供的 OLE DB 数据服务 MsDataShape 来解决此问题。数据服务位于数据使用者和数据提供程序之间,充当提供程序的消费者,并充当使用者的提供程序。MsDataShape 可以执行跨表的连接。请注意,它有自己的特殊 SQL 语法,但只会向数据提供程序发出标准 SQL。此外,它需要使用客户端游标。这意味着 MsDataShape 会提取每个表的副本并执行连接。如果您处理大量数据,这可能会很昂贵。
ADO 事件
如果用户想要制作“实时”图表或报表,他们可以请求数据提供程序在特定表中的数据更新时向他们发送事件。用户必须找到表上的 ConnectionPoint。他们必须创建一个指定所有可能回调的类,请参阅 SensorInterfDlg.h 中的 CrstEvent。(这似乎有些矫枉过正,但 COM 是这样要求的。COM+ 解决了这个问题,但 OLE DB 尚未更新。)然后,ConnectionPoint 会使用请求的类进行 Advise()。请注意,大多数回调都使用了 adStatusUnwantedEvent。还要注意“Update Resync”的设置。这将导致事件被发送到对该表的任何已打开查询。最后,对话框存储在回调类中,以便在回调中轻松更新对话框。
使用 ADO
Microsoft 提供了一些数据绑定控件,以便更轻松地处理数据库。本示例使用数据绑定组合框。组合框指向表 SetRefRowSource(),以及表中的字段 SetListField()。然后,它将在组合框中显示该列的所有值。富文本编辑字段也可以执行类似的操作,但本示例仅正常加载文本。ADO 代码将在发生任何错误时抛出异常。请记住在 ADO 代码周围使用 try/catch 调用。此外,所有打开的连接和 Recordset 都应在退出前关闭。
多使用者
当前数据提供程序已与上面描述的 C++ 编写的数据使用者一起使用。此外,使用 Visual Basic 的独立应用程序也能够访问数据。通过在 Dev Studio 中将 VB 指定为应用程序,可以在 VB 运行时调试提供程序。已生成使用 Crystal Reportsä 的简单报表。请注意,告知 Crystal Reports 提供程序是 ADO 数据库,而不仅仅是 OLE DB 数据库。最后,使用 ChartFXä 编写了一个简单应用程序。ADO 用于从提供程序获取行集,然后直接将其传递给 ChartFX。这显示了为自定义数据提供 OLE DB 接口的强大功能。
致谢
- Len Holgate 撰写了一系列关于编写 OLE DB 提供程序的文章。您可以在 www.codeproject.com/database 找到它们。
- Ben Faul 撰写了一篇关于在 C++ 中使用 SQL 的文章。SQL 解析器是从这篇文章复制的。请参阅 2000 年 3 月的 www.cuj.com。