CODBCRecordset 类






4.91/5 (35投票s)
CODBCRecordset 类旨在完全替代 MFC 项目中所有 ClassWizard 生成的 CRecordset 派生类。
目录
引言
在典型的 MFC 数据库项目中,我们有很多由 ClassWizard 生成的 CRecordset 派生类。本文介绍的 CODBCRecordset 类是所有这些 CRecordset 类的非常易于使用的替代品。CODBCRecordset 派生自 CRecordset,但它没有硬编码数据库字段的数量和类型。
我见过一些实现试图解决这个问题。但是 CODBCRecordset 至少有两个优点
- CODBCRecordset不仅可以用于从数据库获取值,还可以使用 MFC 的方式将值写入数据库。
- 其他实现不能通过一个数据库连接同时打开多个记录集,当数据库是 MS SQL Server 时。在某些情况下,这可能是一个大问题,因为打开新连接在时间和资源方面成本很高。
由于 CODBCRecordset 派生自 CRecordset 并使用其数据交换机制,因此它与 MFC ODBC 类 CDatabase 完全兼容。
每个字段的值都存储在一个 CDBField 对象中。CDBField 类继承自 CDBVariant,并具有一些附加功能,因此易于使用。
CODBCRecordset 和 CDBField 类支持所有数据库数据类型。CDBField 在适当的情况下进行隐式类型转换,以提供的格式供应数据。
以下是 CODBCRecordset 和 CDBField 方法的列表
| CODBCRecordset 类 | |||||||||||||||||||||
| 构造函数 | 与 CRecordset相同,接受CDatabase* | ||||||||||||||||||||
| BOOL Open( LPCTSTR lpszSQL, UINT nOpenType, DWORD dwOptions ); | 打开 记录集lpszSQL是一个返回记录集的 SQL 语句例如: SELECT * FROM tablenamenOpenType是CRecordset的打开类型,请参阅CRecordset::Open()dwOptions是CRecordset的选项,请参阅CRecordset::Open()请注意,与  | ||||||||||||||||||||
| short GetODBCFieldCount() | 返回 记录集中的字段(列)数量。此方法在CRecordset中定义。 | ||||||||||||||||||||
| int GetFieldID( LPCTSTR ) | 根据给定的字段名返回字段索引。不区分大小写。 CRecordset::GetFieldIndexByName()可以工作,但区分大小写。 | ||||||||||||||||||||
| CString GetFieldName( int ) | 根据给定的字段索引返回字段名。 | ||||||||||||||||||||
| CDBField& Field( LPCTSTR )<br /> CDBField& Field( int ) | 通过此方法,您可以获取对内部 CDBField对象的引用,该对象对应于指定的列(有关CDBField的详细信息,请参阅 CDBField 类表)。该方法有两种形式——一种带有参数  这些方法可以用作表达式中的  | ||||||||||||||||||||
| CDBField& operator( LPCTSTR )<br /> CDBField& operator( int ) | 定义了函数运算符,以便于使用该类,并仅调用相应的 Field()方法。函数运算符有两种形式——一种带有参数  这些可以用作表达式中的  | ||||||||||||||||||||
| 
 | 所有这些方法都根据其返回值和数据库底层数据类型进行适当的类型转换。 这些方法仅调用  这些方法有两种形式——一种带有参数  这些不能用作表达式中的  | ||||||||||||||||||||
| CDBField 类 | |||||||||||||||||||||||||
| 构造函数 | 没有 public构造函数。CDBField不能被实例化,除了CODBCRecordset用于内部结构以支持数据交换。这些对象可以通过CODBCRecordset方法访问。 | ||||||||||||||||||||||||
| 
 | 所有这些方法都根据其返回值和数据库底层数据类型进行适当的类型转换(有关数据转换规则,请参阅 AsXXX 方法表)。 没有 Int 数据类型,但  | ||||||||||||||||||||||||
| 赋值运算符 | 定义了接受 bool、unsigned char、short、int、long、COleDateTime和CString的赋值运算符。因此CDBField对象可以是左值。没有接受CLongBinary的赋值运算符,因为 MFC 不支持将CLongBinary值写入数据库。这些赋值运算符将执行到底层数据库列数据类型的适当转换,但CLongBinary除外(有关数据转换规则,请参阅 赋值运算符表)。 | ||||||||||||||||||||||||
| const CString& GetName() | 返回此对象对应的字段名。 | ||||||||||||||||||||||||
| 
 | 每个方法返回 true,如果字段包含相应数据类型的值。没有  没有  | ||||||||||||||||||||||||
| 数据库中的值 | ||||||||||
| NULL | BOOL | UCHAR | SHORT | LONG | SINGLE | DOUBLE | DATE | STRING (字符串) | BINARY | |
| AsBool | false | * | * | * | * | * | * | * | ||
| AsChar | 0x32 | * | * | * | * | * | * | * | ||
| AsShort | 0 | * | * | * | * | * | * | * | ||
| AsInt | 0 | * | * | * | * | * | * | * | ||
| AsLong | 0 | * | * | * | * | * | * | * | ||
| AsFloat | 0.0 | * | * | * | * | * | * | * | ||
| AsDouble | 0.0 | * | * | * | * | * | * | * | ||
| AsDate | null | invalid | invalid | * | * | * | * | * | * | |
| AsString | empty | * | * | * | * | * | * | * | * | * | 
| AsLongBinary | NULL | * | ||||||||
| 空白单元格表示转换不可用,因此代码会断言。 标记为 * 的单元格表示转换可用(有关数据转换规则,请参阅 转换算法表)。 | ||||||||||
| 数据库字段类型 | 赋值运算符的参数 | ||||||||
| bool | unsigned char | short | int | long | float | double | COleDateTime | 字符串 | |
| NULL | |||||||||
| BOOL | * | * | * | * | * | * | * | * | |
| UCHAR | * | * | * | * | * | * | * | * | |
| SHORT | * | * | * | * | * | * | * | * | |
| LONG | * | * | * | * | * | * | * | * | |
| SINGLE | * | * | * | * | * | * | * | * | |
| DOUBLE | * | * | * | * | * | * | * | * | |
| DATE | * | * | |||||||
| STRING (字符串) | * | * | * | * | * | * | * | * | * | 
| BINARY | |||||||||
| 空白单元格表示转换不可用,因此代码会断言。 标记为 * 的单元格表示转换可用(有关数据转换规则,请参阅 转换算法表)。 | |||||||||
如何使用 CODBCRecordset 的示例
应将 ODBCRecordset.h 和 ODBCRecordset.cpp 文件包含到您的项目中。
我通常会在我的 StdAfx.h 文件中包含此行。
#include "ODBCRecordset.h"
以下是一个简单的代码示例,展示了如何使用 CODBCRecordset。
/////////////////////////////////////////////////////////////////////////////
CDatabase    db;
//    This connect string will pop up the ODBC connect dialog
CString        cConnect = "ODBC;";
db.Open( NULL,                //    DSN
     FALSE,                //    Exclusive
     FALSE,                //    ReadOnly
     cConnect,            //    ODBC Connect string
     TRUE                //    Use cursor lib
   );
COleDateTime    dOrderDate;
CODBCRecordset    rs( &db );
rs.Open( "SELECT * FROM Orders \
    WHERE ORDER_DATE > 'jan 1 2000' \
    ORDER BY ORDER_DATE" );
for( ; ! rs.IsEOF(); rs.MoveNext() )
{
//    The choice is yours. You may choose whatever way
//    you want to get the values
//
    //    These return COleDateTime value
    dOrderDate = rs.GetDate( "ORDER_DATE" );
    dOrderDate = rs.Field("ORDER_DATE").AsDate();
    //    These make implicit call to AsDate()
    dOrderDate = rs("ORDER_DATE");
    dOrderDate = rs.Field("ORDER_DATE");
    //    Now edit the fields in the recordset
    rs.Edit();
    rs("ORDER_DATE") = "jan 1 1999";    // Implicit conversion
    rs.Field("ORDER_DATE") = "jan 1 1999";  // Implicit conversion
    rs.Update();
}    //    for(....
//////////////////////////////////////////////////////////////////////////////
如果 ORDER_DATE 在数据库中存储为 datetime 或兼容的数据类型,则值将直接获取。
如果 ORDER_DATE 在数据库中存储为 string 或兼容的数据类型(char、varchar),则值将通过 COleDateTime::ParseDateTime() 方法进行转换。如果转换失败,dOrderDate 将被设置为 COleDatetime::invalid。
打开由 join 语句生成的 结果集 时,可能会有 2 个或更多同名的列。CODBCRecordset 会保留第一个列的名称不变,而其他重复的列会通过添加其重复次数来重命名。未重复的列名将保持不变。例如:
SELECT * FROM Orders, Customers WHERE Orders.CUST_ID = Customers.ID
如果 Orders 表有一个名为 ID 的列,Customers 表有一个名为 ID 的列,CODBCRecordset 会将 Customers 的 ID 重命名为 ID2,而其他所有未重复的列名将保持不变。
好吧,这里有一个技巧:手动重命名列,以确保它们的确切名称,例如:
SELECT Orders.*, Customers.ID as CUSTOMERS_ID
    FROM Orders, Customers 
    WHERE Orders.CUST_ID = Customers.ID
CODBCRecordset 如何工作?
CODBCRecordset 为 结果集 中的所有字段分配存储空间,并使用 MFC 的 记录字段交换 机制,就像从 CRecordset 继承一样,使用 ClassWizard。


