TN053:DAO 数据库类的自定义 DFX 例程
注意
DAO 用于 Access 数据库,并通过 Office 2013 提供支持。 DAO 3.6 是最终版本,被视为已过时。 Visual C++ 环境和向导不支持 DAO(尽管包含 DAO 类且你仍可以使用它们)。 Microsoft 建议对新项目使用 OLE DB 模板或 ODBC 和 MFC。 应只在维护现有应用程序时使用 DAO。
本技术说明介绍 DAO 记录字段交换 (DFX) 机制。 为了帮助了解 DFX 例程中发生的情况,会将 DFX_Text
函数作为示例来详细说明。 作为本技术说明的其他信息来源,你可以查看其他各个 DFX 函数的代码。 你可能不需要像需要自定义 RFX 例程(用于 ODBC 数据库类)那样经常使用自定义DFX例程。
本技术说明包含:
DFX 概述
使用 DAO 记录字段交换和动态绑定的示例
DFX 概述
DAO 记录字段交换机制 (DFX) 用于简化在使用 CDaoRecordset
类时检索和更新数据的过程。 该过程使用 CDaoRecordset
类的数据成员进行简化。 通过派生自 CDaoRecordset
,可以将数据成员添加到表示表或查询中每个字段的派生类。 这种“静态绑定”机制十分简单,但可能不是所有应用程序首选的数据提取/更新方法。 每次更改当前记录时,DFX 都会检索每个绑定字段。 如果要开发不需要在货币更改时提取每个字段的对性能敏感的应用程序,通过 CDaoRecordset::GetFieldValue
和 CDaoRecordset::SetFieldValue
实现的“动态绑定”可能是首选的数据访问方法。
注意
DFX 和动态绑定不相互排斥,因此可以混合使用静态和动态绑定。
示例 1 - 仅使用 DAO 记录字段交换
(假设 CDaoRecordset
— 派生类 CMySet
已打开)
// Add a new record to the customers table
myset.AddNew();
myset.m_strCustID = _T("MSFT");
myset.m_strCustName = _T("Microsoft");
myset.Update();
示例 2 - 仅使用动态绑定
(假设使用 CDaoRecordset
类 rs
并且它已打开)
// Add a new record to the customers table
COleVariant varFieldValue1 (_T("MSFT"),
VT_BSTRT);
//Note: VT_BSTRT flags string type as ANSI,
instead of UNICODE default
COleVariant varFieldValue2 (_T("Microsoft"),
VT_BSTRT);
rs.AddNew();
rs.SetFieldValue(_T("Customer_ID"),
varFieldValue1);
rs.SetFieldValue(_T("Customer_Name"),
varFieldValue2);
rs.Update();
示例 3 — 使用 DAO 记录字段交换和动态绑定
(假设使用 CDaoRecordset
派生类 emp
浏览员工数据)
// Get the employee's data so that it can be displayed
emp.MoveNext();
// If user wants to see employee's photograph,
// fetch it
COleVariant varPhoto;
if (bSeePicture)
emp.GetFieldValue(_T("photo"),
varPhoto);
// Display the data
PopUpEmployeeData(emp.m_strFirstName,
emp.m_strLastName,
varPhoto);
DFX 的工作原理
DFX 机制的工作方式与 MFC ODBC 类使用的记录字段交换 (RFX) 机制类似。 DFX 和 RFX 的原则相同,但存在许多内部差异。 DFX 函数的设计使得几乎所有代码都由各个 DFX 例程共享。 在最高级别,DFX 只执行少量工作。
如果需要,DFX 会构造 SQL SELECT 子句和 SQL PARAMETERS 子句。
DFX 构造 DAO 的
GetRows
函数所使用的绑定结构(稍后将详细介绍)。DFX 管理用于检测脏字段的数据缓冲区(如果使用双缓冲)
DFX 管理 NULL 和 DIRTY 状态数组,并在更新时根据需要设置值。
DFX 机制的核心是 CDaoRecordset
派生类的 DoFieldExchange
函数。 此函数会将调用调度给具有相应操作类型的各个 DFX 函数。 调用 DoFieldExchange
内部 MFC 函数之前,请设置操作类型。 以下列表显示各种操作类型和简要说明。
Operation | 说明 |
---|---|
AddToParameterList |
生成 PARAMETERS 子句 |
AddToSelectList |
生成 SELECT 子句 |
BindField |
设置绑定结构 |
BindParam |
设置参数值 |
Fixup |
设置 NULL 状态 |
AllocCache |
为脏检查分配缓存 |
StoreField |
将当前记录保存到缓存 |
LoadField |
将缓存还原到成员值 |
FreeCache |
释放缓存 |
SetFieldNull |
将字段状态和值设置为 NULL |
MarkForAddNew |
在不是 PSEUDO NULL 时将字段标记为脏 |
MarkForEdit |
在不匹配缓存时将字段标记为脏 |
SetDirtyField |
设置标记为脏的字段值 |
在下一部分中,将更详细地介绍 DFX_Text
的每个操作。
了解 DAO 记录字段交换过程的最重要功能是它使用 CDaoRecordset
对象的 GetRows
函数。 DAO GetRows
函数可以通过多种方式工作。 本技术说明仅简要介绍 GetRows
,因为它超出了本技术说明的讨论范围。
DAO GetRows
可以通过多种方式工作。
它可以一次提取数据的多个记录和多个字段。 这样可以在处理大型数据结构以及结构中数据的每个字段和每个数据的相应偏移十分复杂的情况下,更快地进行数据访问。 MFC 不利用这种多记录提取机制。
GetRows
的另一种工作方式是允许程序员为一个数据记录的每个字段的已检索数据指定绑定地址。对于可变长度列,DAO 还会“回调”到调用方中,以便调用方可以分配内存。 这第二个功能的好处是可最大程度地减少数据的副本数,并允许将数据直接存储到类的成员(
CDaoRecordset
派生类)。 这第二种机制是 MFC 用于绑定到CDaoRecordset
派生类中的数据成员的方法。
自定义 DFX 例程的作用
从此讨论中可以明显看出,在任何 DFX 函数中实现的最重要操作必须是能够设置所需数据结构以成功调用 GetRows
。 DFX 函数还必须支持一些其他操作,但没有一个操作如同为 GetRows
调用正确做好准备那样重要或复杂。
联机文档中介绍了 DFX 的使用。 本质上有两个要求。 首先,对于每个绑定字段和参数,必须将成员添加到 CDaoRecordset
派生类。 在此之后,应替代 CDaoRecordset::DoFieldExchange
。 请注意,成员的数据类型十分重要。 它应与数据库中字段的数据匹配,或者至少可转换为该类型。 例如,数据库中的数字字段(如长整型)始终可以转换为文本并绑定到 CString
成员,但数据库中的文本字段不一定可以转换为数字表示形式(如长整型)并绑定到长整型成员。 DAO 和 Microsoft Jet 数据库引擎负责转换(而不是 MFC)。
DFX_Text 的详细信息
如前所述,说明 DFX 的工作原理的最佳方法是演练示例。 为此,浏览 DFX_Text
的内部内容应该可以很好地帮助至少对 DFX 具有基本了解。
AddToParameterList
此操作生成 Jet 所需的 SQL PARAMETERS 子句(“
Parameters <param name>, <param type> ... ;
”)。 每个参数都会进行命名和类型化(在 RFX 调用中指定)。 请参阅CDaoFieldExchange::AppendParamType
函数以查看各种类型的名称。 对于DFX_Text
,使用的类型为文本。AddToSelectList
生成 SQL SELECT 子句。 这非常直接,因为 DFX 调用指定的列名只是进行追加(“
SELECT <column name>, ...
”)。BindField
最复杂的操作。 如前所述,这是设置
GetRows
所使用的 DAO 绑定结构的位置。 从DFX_Text
中的代码可以看出,结构中的信息类型包含所使用的 DAO 类型(对于DFX_Text
为 DAO_CHAR 或 DAO_WCHAR)。 此外,还会设置所使用的绑定类型。 在前面的部分中,只简要介绍了GetRows
,但足以说明 MFC 使用的绑定类型始终是直接地址绑定 (DAOBINDING_DIRECT)。 此外,对于可变长度列绑定(如DFX_Text
),会使用回调绑定,以便 MFC 可以控制内存分配,并指定正确长度的地址。 这意味着 MFC 始终可以告诉 DAO 将数据置于何处,从而允许直接绑定到成员变量。 绑定结构的其余部分使用内存分配回调函数的地址和列绑定的类型(按列名绑定)这类内容进行填充。BindParam
这是简单操作,它使用在参数成员中指定的参数值调用
SetParamValue
。Fixup
为每个字段填充 NULL 状态。
SetFieldNull
此操作仅将每个字段状态标记为 NULL,并将成员变量的值设置为 PSEUDO_NULL。
SetDirtyField
对标记为脏的每个字段调用
SetFieldValue
。
其余所有操作仅处理使用数据缓存。 数据缓存是当前记录中的额外数据缓冲区,用于简化某些操作。 例如,可以自动检测“脏”字段。 如联机文档中所述,它可以完全关闭或在字段级别关闭。 缓冲区的实现利用了映射。 此映射用于将动态分配的数据副本与“绑定”字段(或 CDaoRecordset
派生数据成员)的地址匹配。
AllocCache
动态分配缓存的字段值,并将它添加到映射。
FreeCache
删除缓存的字段值,并将它从映射中移除。
StoreField
将当前字段值复制到数据缓存中。
LoadField
将缓存的值复制到字段成员中。
MarkForAddNew
检查当前字段值是否非 NULL,并在需要时将它标记为脏。
MarkForEdit
将当前字段值与数据缓存进行比较,并在需要时标记为脏。
提示
针对标准数据类型,在现有 DFX 例程上为自定义 DFX 例程建模。