注释
DAO 与 Access 数据库一起使用,并通过 Office 2013 提供支持。 DAO 3.6 是最终版本,它被视为已过时。 Visual C++ 环境和向导不支持 DAO(尽管包含 DAO 类,但仍可使用它们)。 Microsoft建议对新项目使用 OLE DB 模板 或 ODBC 和 MFC 。 应仅在维护现有应用程序时使用 DAO。
此技术说明介绍了 DAO 记录字段交换(DFX)机制。 为了帮助了解 DFX 例程中发生的情况,该 DFX_Text
函数将详细解释为示例。 作为此技术说明的其他信息来源,可以检查其他单个 DFX 函数的代码。 你可能不需要自定义 DFX 例程,因为可能需要自定义 RFX 例程(与 ODBC 数据库类一起使用)。
此技术说明包含:
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 记录字段交换和动态绑定
(假设使用 -derived 类emp
浏览员工数据CDaoRecordset
)
// 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 函数之前,请设置作类型。 以下列表显示了各种作类型和简要说明。
操作 | DESCRIPTION |
---|---|
AddToParameterList |
Builds PARAMETERS 子句 |
AddToSelectList |
生成 SELECT 子句 |
BindField |
设置绑定结构 |
BindParam |
设置参数值 |
Fixup |
设置 NULL 状态 |
AllocCache |
为脏检查分配缓存 |
StoreField |
将当前记录保存到缓存 |
LoadField |
将缓存还原到成员值 |
FreeCache |
释放缓存 |
SetFieldNull |
将字段状态和值设置为 NULL |
MarkForAddNew |
如果字段不是伪 NULL,则标记脏字段 |
MarkForEdit |
如果不匹配缓存,则标记脏字段 |
SetDirtyField |
设置标记为脏的字段值 |
在下一部分中,将更详细地 DFX_Text
介绍每个作。
了解 DAO 记录字段交换过程的最重要功能是它使用 GetRows
对象的函数 CDaoRecordset
。 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
最复杂的作。 如前所述,这是设置 DAO 绑定结构
GetRows
的位置。 从结构中的信息类型中看到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 例程建模。