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

CODBCRecordset 类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (35投票s)

2000 年 4 月 12 日

CPOL
viewsIcon

473772

downloadIcon

3867

CODBCRecordset 类旨在完全替代 MFC 项目中所有 ClassWizard 生成的 CRecordset 派生类。

目录

引言

在典型的 MFC 数据库项目中,我们有很多由 ClassWizard 生成的 CRecordset 派生类。本文介绍的 CODBCRecordset 类是所有这些 CRecordset 类的非常易于使用的替代品。CODBCRecordset 派生自 CRecordset,但它没有硬编码数据库字段的数量和类型。

我见过一些实现试图解决这个问题。但是 CODBCRecordset 至少有两个优点

  1. CODBCRecordset 不仅可以用于从数据库获取值,还可以使用 MFC 的方式将值写入数据库。
  2. 其他实现不能通过一个数据库连接同时打开多个记录集,当数据库是 MS SQL Server 时。在某些情况下,这可能是一个大问题,因为打开新连接在时间和资源方面成本很高。

由于 CODBCRecordset 派生自 CRecordset 并使用其数据交换机制,因此它与 MFC ODBC 类 CDatabase 完全兼容。

每个字段的值都存储在一个 CDBField 对象中。CDBField 类继承自 CDBVariant,并具有一些附加功能,因此易于使用。

CODBCRecordsetCDBField 类支持所有数据库数据类型。CDBField 在适当的情况下进行隐式类型转换,以提供的格式供应数据。

以下是 CODBCRecordsetCDBField 方法的列表

CODBCRecordset 类
构造函数 CRecordset 相同,接受 CDatabase*
BOOL Open( LPCTSTR lpszSQL, UINT nOpenType, DWORD dwOptions ); 打开 记录集
lpszSQL 是一个返回 记录集 的 SQL 语句
例如: SELECT * FROM tablename
nOpenType CRecordset 的打开类型,请参阅 CRecordset::Open()dwOptions CRecordset 的选项,请参阅 CRecordset::Open()

请注意,与 CRecordset::Open() 相比,lpszSQL nOpenType 的位置已互换。

short GetODBCFieldCount() 返回 记录集 中的字段(列)数量。此方法在 CRecordset 中定义。
int GetFieldID( LPCTSTR ) 根据给定的字段名返回字段索引。不区分大小写。CRecordset::GetFieldIndexByName() 可以工作,但区分大小写。
CString GetFieldName( int ) 根据给定的字段索引返回字段名。
CDBField& Field( LPCTSTR )<br /> CDBField& Field( int ) 通过此方法,您可以获取对内部 CDBField 对象的引用,该对象对应于指定的列(有关 CDBField 的详细信息,请参阅 CDBField表)。

该方法有两种形式——一种带有参数 LPCTSTR szName ,指定列名;另一种带有参数 int nID ,指定记录集中的列索引。

这些方法可以用作表达式中的 左值。因此,您可以将值写入数据库。

CDBField& operator( LPCTSTR )<br /> CDBField& operator( int ) 定义了函数运算符,以便于使用该类,并仅调用相应的 Field() 方法。

函数运算符有两种形式——一种带有参数 LPCTSTR szName,指定列名;另一种带有参数 int nID,指定记录集中的列索引。

这些可以用作表达式中的 左值。因此,您可以将值写入数据库。

bool GetBool()
unsigned char GetChar()
short GetShort()
int GetInt()
long GetLong()
float Getfloat()
double GetDouble()
COleDateTime GetDate()
CString GetString()
CLongBinary* GetBinary()
所有这些方法都根据其返回值和数据库底层数据类型进行适当的类型转换。

这些方法仅调用 Field().AsXXX()
(有关 CDBField 的详细信息,请参阅 CDBField 类表)。

这些方法有两种形式——一种带有参数 LPCTSTR szName,指定列名;另一种带有参数 int nID,指定 记录集 中的列索引。

这些不能用作表达式中的 左值

CDBField 类
构造函数 没有 public 构造函数。CDBField 不能被实例化,除了 CODBCRecordset 用于内部结构以支持数据交换。这些对象可以通过 CODBCRecordset 方法访问。
bool AsBool()
unsigned char AsChar()
short AsShort()
int AsInt()
long AsLong()
float AsFloat()
double AsDoble()
COleDateTime AsDate()
CString AsString()
CLongBinary* AsBinary()
所有这些方法都根据其返回值和数据库底层数据类型进行适当的类型转换(有关数据转换规则,请参阅 AsXXX 方法表)。

没有 Int 数据类型,但 AsInt() 等同于 AsLong()

赋值运算符 定义了接受 bool、unsigned charshortintlongCOleDateTimeCString 的赋值运算符。因此 CDBField 对象可以是 左值。没有接受 CLongBinary 的赋值运算符,因为 MFC 不支持将 CLongBinary 值写入数据库。这些赋值运算符将执行到底层数据库列数据类型的适当转换,但 CLongBinary 除外(有关数据转换规则,请参阅 赋值运算符表)。
const CString& GetName() 返回此对象对应的字段名。
bool IsNull()
bool IsBool()
bool IsChar()
bool IsShort()
bool IsInt()
bool IsLong()
bool IsFloat()
bool IsDouble()
bool IsNumber()
bool IsDate()
bool IsString()
bool IsBinary()
每个方法返回 true,如果字段包含相应数据类型的值。

没有 Number 数据类型,但如果 IsShort() || IsLong() || IsFloat() || IsDouble(),则 IsNumber() 返回 true

没有 Int 数据类型,但如果 IsLong() 返回 true,则 IsInt() 返回 true

AsXXX 方法进行的转换

 

数据库中的值

  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                  
空白单元格表示转换不可用,因此代码会断言。
标记为 * 的单元格表示转换可用(有关数据转换规则,请参阅 转换算法表)。
转换算法
字符串布尔值 比较 字符串 的第一个字符是否为 'T'
字符布尔值 比较字符是否为 'T'
布尔值字符串 String = (bVal) ? 'T' : 'F'
布尔值字符 Char = (bVal) ? 'T' : 'F'
字符串 到 数字 适当的 atoX() 函数
数字 到 字符串 使用适当格式说明符 stringCString::Format() 方法
字符串日期 COleDateTime::ParseDateTime() 方法
日期字符串 COleDateTime::Format() 方法

如何使用 CODBCRecordset 的示例

应将 ODBCRecordset.hODBCRecordset.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 或兼容的数据类型(charvarchar),则值将通过 COleDateTime::ParseDateTime() 方法进行转换。如果转换失败,dOrderDate 将被设置为 COleDatetime::invalid

打开由 join 语句生成的 结果集 时,可能会有 2 个或更多同名的列。CODBCRecordset 会保留第一个列的名称不变,而其他重复的列会通过添加其重复次数来重命名。未重复的列名将保持不变。例如:

SELECT * FROM Orders, Customers WHERE Orders.CUST_ID = Customers.ID

如果 Orders 表有一个名为 ID 的列,Customers 表有一个名为 ID 的列,CODBCRecordset 会将 CustomersID 重命名为 ID2,而其他所有未重复的列名将保持不变。

好吧,这里有一个技巧:手动重命名列,以确保它们的确切名称,例如:

SELECT Orders.*, Customers.ID as CUSTOMERS_ID
    FROM Orders, Customers 
    WHERE Orders.CUST_ID = Customers.ID

CODBCRecordset 如何工作?

CODBCRecordset结果集 中的所有字段分配存储空间,并使用 MFC 的 记录字段交换 机制,就像从 CRecordset 继承一样,使用 ClassWizard

© . All rights reserved.