注释
自联机文档中首次包含此说明以来,尚未更新以下技术说明。 因此,某些过程和主题可能过期或不正确。 有关最新信息,建议在在线文档索引中搜索您感兴趣的主题。
此说明介绍了记录字段交换(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 上执行,反之亦然(例如调用 BindParam
outputColumn)。 此外, IsFieldType
自动跟踪 outputColumns (m_nFields)和参数(m_nParams)的计数。