DataLayer - 免费 ODBC 库
关于一个简单的 ODBC SDK 包装库的文章。
引言
本文介绍了一个简单的 ODBC 库(DLL),可以在 MFC 或非 MFC 应用程序中使用,用于数据源访问和执行 SQL 语句,而无需了解数据源的性质(例如 MS Access、FoxBase、SQL Server、MySQL 等),只要有相应的 ODBC 驱动程序即可。如今,几乎所有主要数据库系统都提供了 ODBC 驱动程序。
背景
为了完成这项任务,存在着大量的不同解决方案。你可以在 CodeProject 上找到它们,也可以在互联网上找到(有些是免费的,有些则不是)。MFC 针对这项任务的解决方案是众所周知的 CDatabase
和 CRecordset
类,它们为我们提供了在处理 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();
连接方法中最重要的参数是 dsn
和 user
(如果需要的话,否则可以为 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);
主要用于 INSERT
、UPDATE
或 DELETE
语句。你也可以在 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
对象那样,你可以获取第一条、最后一条或前一条记录,每次调用后,你都会获得结果集中的下一条记录),这意味着你希望在单次遍历中从结果集的开头到结尾。
接下来,如果你想要你的数据,你需要提供变量来存储它。这些变量在上面的例子中由 data1
和 data2
提供。它们必须是与结果集中每列返回数据的类型**兼容**的类型。然后,你可以调用 _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。