TN043:RFX 例程

注释

自联机文档中首次包含此说明以来,尚未更新以下技术说明。 因此,某些过程和主题可能过期或不正确。 有关最新信息,建议在在线文档索引中搜索您感兴趣的主题。

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

记录字段交换概述

所有记录集字段函数都使用C++代码完成。 没有特殊资源或 magic 宏。 机制的核心是必须在每个派生的记录集类中重写的虚拟函数。 它始终以以下形式找到:

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 的方法。

注释

Recordset 字段函数设计为仅适用于 CRecordset 类。 它们通常不能由任何其他 MFC 类使用。

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

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

调用的每个函数 DoFieldExchange (例如 SetFieldNull,) IsFieldDirty围绕调用 DoFieldExchange执行自己的初始化。

工作原理

无需了解以下内容即可使用记录字段交换。 但是,了解后台的工作原理将有助于编写自己的交换过程。

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

  • BindParam — 指示 ODBC 应检索参数数据的位置

  • BindFieldToColumn — 指示 ODBC 必须检索/存储 outputColumn 数据的位置

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

  • MarkForAddNew — 如果自 AddNew 调用后值已更改,则标记脏

  • MarkForUpdate — 如果自“编辑”调用后值已更改,则标记脏标记

  • 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 上执行,反之亦然(例如调用 BindParamoutputColumn)。 此外, IsFieldType 自动跟踪 outputColumnsm_nFields)和参数(m_nParams)的计数。

另请参阅

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