TN043:RFX 例程

注意

以下技术说明在首次包括在联机文档中后未更新。 因此,某些过程和主题可能已过时或不正确。 要获得最新信息,建议你在联机文档索引中搜索热点话题。

本说明介绍记录字段交换 (RFX) 体系结构。 此外介绍如何编写 RFX_ 过程

记录字段交换概述

所有记录集字段函数都是用 C++ 代码执行的。 没有特殊的资源或神奇的宏。 该机制的核心是必须在每个派生记录集类中重写的虚拟函数。 它的形式始终如下:

void CMySet::DoFieldExchange(CFieldExchange* pFX)
{
    //{{AFX_FIELD_MAP(CMySet)
        <recordset exchange field type call>
        <recordset exchange function call>
    //}}AFX_FIELD_MAP
}

特殊格式 AFX 注释允许 ClassWizard 在此函数中查找和编辑代码。 与 ClassWizard 不兼容的代码应放置在特殊格式注释之外。

在上面的示例中,recordset_exchange_field_type_call 采用以下形式<>:

pFX->SetFieldType(CFieldExchange::outputColumn);

recordset_exchange_function_call 采用以下形式<>:

RFX_Custom(pFX, "Col2", m_Col2);

大多数 RFX_ 函数具有上面所示的三个参数,但有些函数(例如 RFX_TextRFX_Binary)具有额外的可选参数

每个 DoDataExchange 函数可能包含多个 RFX_

有关 MFC 提供的所有记录集字段交换例程的列表,请参阅“afxdb.h”。

记录集字段调用是注册内存位置(通常是数据成员)以存储 CMySet 类的字段数据的一种方式。

说明

记录集字段函数只能与 CRecordset 类一起使用。 它们通常不可由任何其他 MFC 类使用。

数据的初始值在标准 C++ 构造函数中设置,通常在具有 //{{AFX_FIELD_INIT(CMylSet)//}}AFX_FIELD_INIT 注释的块中设置。

每个 RFX_ 函数必须支持各种操作,从返回字段的脏状态到存档字段以准备编辑字段

每个调用 DoFieldExchange 的函数(例如 SetFieldNullIsFieldDirty)都会围绕 DoFieldExchange 调用执行自身的初始化。

工作原理

无需了解以下知识即可使用记录字段交换。 但了解幕后工作原理有助于编写自己的交换过程。

DoFieldExchange 成员函数非常类似于 Serialize 成员函数 — 它负责为外部窗体(本例中为 ODBC 查询结果中的列)获取类中成员数据,或者将外部窗体数据设置为类中成员数据。 pFX 参数是执行数据交换的上下文,类似于 CObject::Serialize 的 CArchive 参数。 pFX(一个 CFieldExchange 对象)有一个操作指示符,该指示符类似于 CArchive 方向标志,但它是该标志的泛化。 RFX 函数可能必须支持以下操作:

  • BindParam — 指示 ODBC 应在何处检索参数数据

  • BindFieldToColumn — 指示 ODBC 必须在何处检索/存放 outputColumn 数据

  • Fixup —设置 CString/CByteArray 长度,设置 NULL 状态位

  • MarkForAddNew — 如果值自 AddNew 调用以来发生更改,则标记为脏

  • MarkForUpdate — 如果值自 Edit 调用以来发生更改,则标记为脏

  • Name — 为标记为脏的字段追加字段名称

  • NameValue — 为标记为脏的字段追加“<列名>=”

  • Value — 追加 "" 后接分隔符,例如“,”或“ ”

  • SetFieldDirty — 设置状态位脏(即已更改)字段

  • SetFieldNull — 设置状态位用于指示字段的 null 值

  • IsFieldDirty — 脏状态位的返回值

  • IsFieldNull — null 状态位的返回值

  • IsFieldNullable — 如果字段可以包含 NULL 值,则返回 TRUE

  • StoreField — 存档字段值

  • LoadField — 重新加载存档字段值

  • GetFieldInfoValue — 返回有关字段的一般信息

  • GetFieldInfoOrdinal — 返回有关字段的一般信息

用户扩展

可通过多种方式扩展默认 RFX 机制。 则可以

  • 添加新数据类型。 例如:

    CBookmark
    
  • 添加新的交换过程 (RFX_)。

    void AFXAPI RFX_Bigint(CFieldExchange* pFX,
        const char *szName,
        BIGINT& value);
    
  • DoFieldExchange 成员函数按条件包含其他 RFX 调用或任何其他有效的 C++ 语句。

    while (posExtraFields != NULL)
    {
        RFX_Text(pFX,
        m_listName.GetNext(posExtraFields),
        m_listValue.GetNext(posExtraValues));
    }
    

注意

此类代码不能由 ClassWizard 编辑,只应在特殊格式注释之外使用。

编写自定义 RFX

若要编写自己的自定义 RFX 函数,建议复制现有的 RFX 函数并根据目的进行修改。 选择正确的 RFX 进行复制可以简化工作。 某些 RFX 函数具有一些独特的属性,在确定复制哪个函数时应考虑这些属性。

RFX_LongRFX_Int:最简单的 RFX 函数。 数据值不需要任何特殊解释,数据大小是固定的。

RFX_SingleRFX_Double:与上面的 RFX_Long 和 RFX_Int 一样,这些函数非常简单,可以广泛使用默认实现。 但是,它们存储在 dbflt.cpp 而不是 dbrfx.cpp 中,以便仅在显式引用它们时才加载运行时浮点库。

RFX_TextRFX_Binary:这两个函数预先分配一个静态缓冲区来保存字符串/二进制信息,必须将这些缓冲区注册到 ODBC SQLBindCol,而不要注册 &value。 正因如此,这两个函数具有很多特殊情况代码。

RFX_Date:ODBC 在自身的 TIMESTAMP_STRUCT 数据结构中返回日期和时间信息。 此函数动态分配一个 TIMESTAMP_STRUCT 作为发送和接收日期时间数据的“代理”。 各种操作必须在 C++ CTime 对象与 TIMESTAMP_STRUCT 代理之间传输日期和时间信息。 此函数因而变得相当复杂,但它很好地示范了如何使用代理进行数据传输。

RFX_LongBinary:这是唯一一个不使用列绑定来接收和发送数据的类库 RFX 函数。 此函数忽略 BindFieldToColumn 操作,而是在 Fixup 操作期间分配存储来保存传入的 SQL_LONGVARCHAR 或 SQL_LONGVARBINARY 数据,然后执行 SQLGetData 调用以将值检索到分配的存储中。 准备将数据值发送回数据源时(例如 NameValue 和 Value 操作),此函数使用 ODBC 的 DATA_AT_EXEC 功能。 有关如何使用 SQL_LONGVARBINARY 和 SQL_LONGVARCHARs 的详细信息,请参阅技术说明 45

当你编写自己的 RFX_ 函数时,通常可以使用 CFieldExchange::Default 来实现给定的操作。 查看相关操作的 Default 实现。 如果该实现执行你要在 RFX_ 函数中编写的操作,则可以委托给 CFieldExchange::Default。 可以在 dbrfx.cpp 中查看调用 CFieldExchange::Default 的示例

必须在 RFX 函数的开头调用 IsFieldType,并在它返回 FALSE 时立即返回。 此机制可防止对 outputColumns 执行参数操作,反之亦然(例如对 outputColumn 调用 BindParam。 此外,IsFieldType 会自动跟踪 outputColumns (m_nFields) 和参数 (m_nParams) 的计数

另请参阅

按编号列出的技术说明
按类别列出的技术说明