注释
自联机文档中首次包含此说明以来,尚未更新以下技术说明。 因此,某些过程和主题可能过期或不正确。 有关最新信息,建议在在线文档索引中搜索您感兴趣的主题。
此说明介绍了记录字段交换(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_Text 和 RFX_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::Serialize。
pFX(一个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 值,则返回 TRUEStoreField— 存档字段值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_Long 和 RFX_Int:这是最简单的 RFX 函数。 数据值不需要任何特殊解释,并且数据大小是固定的。
RFX_Single 和 RFX_Double:与上述RFX_Long和RFX_Int一样,这些函数很简单,可以广泛使用默认实现。 但是,它们存储在dbflt.cpp而不是dbrfx.cpp中,以便仅在显式引用运行时浮点库时启用加载。
RFX_Text 和 RFX_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 自动跟踪 outputColumns (m_nFields)和参数(m_nParams)的计数。