65.9K
CodeProject 正在变化。 阅读更多。
Home

DataLayer - 免费 ODBC 库

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (24投票s)

2006 年 1 月 10 日

CPOL

7分钟阅读

viewsIcon

140509

downloadIcon

4918

关于一个简单的 ODBC SDK 包装库的文章。

DataLayer Test

引言

本文介绍了一个简单的 ODBC 库(DLL),可以在 MFC 或非 MFC 应用程序中使用,用于数据源访问和执行 SQL 语句,而无需了解数据源的性质(例如 MS Access、FoxBase、SQL Server、MySQL 等),只要有相应的 ODBC 驱动程序即可。如今,几乎所有主要数据库系统都提供了 ODBC 驱动程序。

背景

为了完成这项任务,存在着大量的不同解决方案。你可以在 CodeProject 上找到它们,也可以在互联网上找到(有些是免费的,有些则不是)。MFC 针对这项任务的解决方案是众所周知的 CDatabaseCRecordset 类,它们为我们提供了在处理 ODBC 数据源时极大的自由度,并且在 MSDN 中有详细的文档。那么,现在的问题是,当你已经拥有这些类时,为什么还要使用这个库呢?事实是,如果你在 MFC 下工作,你可能会很满意,因为你已经拥有了一切,但如果不是呢?接着,对于你想访问的数据库中的每个表,你都需要将项目连接到它,并且类向导每次都会向你的项目中添加一个新类。但如果我的数据库有 100 个或更多的表呢?而且,最重要的一点(DataLayer 库开发的原因),如果你的表在项目开发过程中发生了修改怎么办?你很可能需要手动编写所有修改到代表数据库表的生成类中。这可能非常枯燥,对吧?

如果你想在运行时连接到某个数据源,并且想知道有哪些表,表有哪些列,最后,想查看表中不同类型的数据?也许,你想在运行时创建或修改(或删除)表?

你需要一个工具来执行此类数据源访问,并且在日常工作中,使用 ODBC SDK 并不是一件令人愉快的事情。这个库就代表了这样一个包装器,所以你可以毫不费力地执行所有数据库任务。当然,你必须熟悉 SQL 语法才能执行查询。

关于 DataLayer 库内部类命名的说明

请注意,我选择这些以 _Z 开头的名称在实现上并没有什么特别好的理由。所以,你会遇到 _ZConnection_ZRecord_ZColumnInfo_ZTableInfo 类和结构。无论如何,如果你不喜欢,你可以随意重命名。

使用代码

要在你的项目中使用这个 DLL 库,你需要包含头文件 DataLayer.h,并将编译好的模块 DataLayer.dll 复制到你的可执行文件输出目录。或者,你可以将其复制到 Windows 文件夹。无论如何,现在你将能够实例化 DataLayer 库中的某些(但不是全部)类。最后要做的是将你的项目链接到静态库 DataLayer.lib。你可以在下载部分(上面)找到编译好的库模块,以及一个没有任何额外模块的测试项目,所以你需要同时下载两者才能构建测试解决方案。或者,你也可以只下载编译好的模块并构建自己的解决方案。你还会找到库源代码的链接,以便自己编译。

#include "DataLayer.h"

连接到数据源

有一个名为 _ZConnection 的简单类可以提供给你这个功能

// Connect to the data source
_ZConnection zConnection;
BOOL bConnected = zConnection.Connect(dsn, user, authorization);

此调用中的参数是 ODBC 数据源名称 (dsn)、用户名 (user) 和密码 (authorization)。如果连接建立成功,该方法将返回 TRUE,否则返回 FALSE。你也可以随时通过调用来检查连接状态

BOOL bConnected = zConnection.IsConnected();

连接方法中最重要的参数是 dsnuser(如果需要的话,否则可以为 NULL)。如果不需要密码,则可以为 NULL

从数据源断开连接

要断开连接,只需使用

zConnection.Disconnect();

这将释放连接对象中分配的所有资源。但是,请记住调用它。

查询数据源中的表

也许你想知道数据源中有哪些表。要找出答案,你需要为 _ZTableInfo 类型的缓冲区分配一些内存,并将其作为参数传递,如下面的示例

_ZTableInfo tableInfo[100];
int tiSize;
BOOL bResult = zConnection.GetTableInfo(tableInfo, tiSize);

tiSize 变量中,调用此函数后,你将获得数据源中表的精确数量,而 tableInfo 缓冲区将填充有关数据源中每个表的信息。这个结构定义如下

/* _ZTableInfo struct definition */
struct _ZTableInfo
{
    SQLVARCHAR catalogName[1024];
    SQLVARCHAR schemaName[1024];
    SQLVARCHAR tableName[1024];
    SQLVARCHAR tableType[1024];
    SQLVARCHAR tableRemarks[1024];
};

这是枚举数据源表的一种简单方法。

直接执行 SQL 语句

如果你想修改数据库表中的数据,这样做是有意义的。如果你想获得结果集,则没有意义。所以,你可以写成这样

// sqlStatement variable is defined somewhere else
BOOL bResult = zConnection.ExecuteSQL(sqlStatement);

主要用于 INSERTUPDATEDELETE 语句。你也可以在 SELECT 语句中使用它,但有一个小问题:你**看不到**任何结果。现在你已经看到了如何添加、更新或删除数据库中的记录。现在,是时候使用一个新的 DataLayer 库对象来从数据源检索数据了。

处理结果集

该对象称为 _ZRecord,用于数据检索,如下面的示例

_ZRecord zRecord(zConnection);
BOOL bResult = zRecord.ExecuteSQL(sqlStatement);

我建议你在这里使用 SELECT 语句。然后,如果查询成功,返回值将是 TRUE,你应该能够访问返回的数据。使用一个简单的循环,如下所示

// data1 and data2 are variables of the type that is compatible
// with the type of the data in the requested column
while (zRecord.Move())
{
      // columnName variable is a known name
      // of the column in the returned result set
      data1 = (data1_type)zRecord.ColumnByName(columnName);

      // columnIndex variable is a known index
      // of the column in the returned result set
      data2 = (data2_type)zRecord.ColumnByIndex(columnIndex);
}

如果你对这段代码感到困惑,我将解释。你将不断调用 _ZRecord 对象的 Move() 方法,直到你到达返回结果集的末尾。这是一种直接的方法(_ZRecord 对象不像 CRecordset 对象那样,你可以获取第一条、最后一条或前一条记录,每次调用后,你都会获得结果集中的下一条记录),这意味着你希望在单次遍历中从结果集的开头到结尾。

接下来,如果你想要你的数据,你需要提供变量来存储它。这些变量在上面的例子中由 data1data2 提供。它们必须是与结果集中每列返回数据的类型**兼容**的类型。然后,你可以调用 _ZRecord 对象的 ColumnByName()ColumnByIndex() 方法。在前者中,你传递结果集中列的**精确**(不区分大小写)名称,在后者中,你传递一个小于结果集中返回列数量的列索引。别担心,如果你犯了错误,你将得到一个 NULL 值。无论如何,由于这些方法返回一个通用类型(VOID)的对象,因此需要进行显式转换。

如果你想知道返回结果集中列的确切数量,可以这样做

int columnNumber = zRecord.GetColumnNumber();

如果知道结果集中列的名称,上面的代码就没问题。但如果不知道呢?在这种情况下,你可以使用以下方法之一

_ZColumnInfo columnInfo1, columnInfo2;
columnInfo1 = zRecord.GetColumnInfo(columnName);
columnInfo2 = zRecord.GetColumnInfo(columnIndex);

_ZColumnInfo 结构如下所示

/* _ZColumnInfo struct definition */
struct _ZColumnInfo
{
    SQLCHAR columnName[256];
    SQLSMALLINT columnDataType;
    SQLSMALLINT columnNullable;
    SQLUINTEGER columnDataSize;
};

如你所见,通过这种方式,你将获得关于列的所有必要信息。

结论

正如你所见,这个小库将为你提供足够的自由度来轻松执行各种数据库任务。它几乎拥有 MFC ODBC 数据库类的所有内置功能,甚至更多。它不是光标类型的。它可以应用于所有具有现有 ODBC 驱动程序的任何数据源。我在 MS Access 和 MySQL 数据库系统上进行了测试,在执行简单任务时没有发现任何问题,但请记住,可能存在一些例外情况,在这种情况下,请给我写信。

该库也很轻量级,因为(你肯定会注意到)返回值中没有错误描述。它是为了尽可能简单而构建的,但下次,我可能会稍微复杂化一些。

关注点

在处理这个项目时,我发现 ODBC SDK 并不是一个令人愉快的工作工具,但它也有其光明的一面。无论如何,有了这个实现,我未来的代码将大大减少,并且我在处理返回的结果集时将获得更多自由。我的下一步将是实现与你在这里看到的相同的功能,但这次将使用 OLEDB SDK。

历史

  • DataLayer 库 v1.0。
© . All rights reserved.