目录
CRecordset类代表一个记录集,是MFC的ODBC类中最重要、功能最强大的类。
包含头文件 #include <afxdb.h>
1. 动态集、快照、光标和光标库
在多任务操作系统或网络环境中,多个用户可以共享同一个数据源。共享数据的一个主要问题是如何协调各个用户对数据源的修改。例如,当某一个应用改变了数据源中的记录时,别的连接至该数据源的应用应该如何处理。对于这个问题,基于MFC的ODBC应用程序可以采取几种不同的处理办法,这将由程序采用哪种记录集决定。
记录集主要分为快照(Snapshot) 和动态集(Dynaset)两种,CRecordset类对这两者都支持。这两种记录集的不同表现在它们对别的应用改变数据源记录采取了不同的处理方法。
快照型记录集提供了对数据的静态视。当别的用户改变了记录时(包括修改、添加和删除),快照中的记录不受影响,也就是说,快照不反映别的用户对数据源记录的改变,直到调用了CRecordset::Requery重新查询后,快照才会反映变化。对于象产生报告或执行计算这样的不希望中途变动的工作,快照是很有用的。需要指出的是,快照的这种静态特性是相对于别的用户而言的,它会正确反映由本身用户对记录的修改和删除,但对于新添加的记录直到调用Requery后才能反映到快照中。
动态集提供了数据的动态视。当别的用户修改或删除了记录集中的记录时,会在动态集中反映出来:当滚动到修改过的记录时对其所作的修改会立即反映到动态集中,当记录被删除时,MFC代码会跳过记录集中的删除部分。对于其它用户添加的记录,直到调用Requery时,才会在动态集中反映出来。本身应用程序对记录的修改、添加和删除会反映在动态集中。当数据必须是动态的时侯,使用动态集是最适合的。例如,在一个火车票联网售票系统中,显然应该用动态集随时反映出共享数据的变化。
在记录集中滚动,需要有一个标志来指明滚动后的位置(当前位置)。ODBC驱动程序会维护一个光标,用来跟踪记录集的当前记录,可以把光标理解成跟踪记录集位置的一种机制。
光标库(Cursor Library)是处于ODBC驱动程序管理器和驱动程序之间的动态链接库(ODBCCR32.DLL)。光标库的主要功能是支持快照以及为底层驱动程序提供双向滚动能力,高层次的驱动程序不需要光标库,因为它们是可滚动的。光标库管理快照记录的缓冲区,该缓冲区反映本程序对记录的修改和删除,但不反映其它用户对记录的改变,由此可见,快照实际上相当于当前的光标库缓冲区。
应注意的是,快照是一种静态光标(Static Cursor)。静态光标直到滚动到某个记录才能取得该记录的数据。因此,要保证所有的记录都被快照,可以先滚动到记录集的末尾,然后再滚动到感兴趣的第一个记录上。这样做的缺点是滚动到末尾需要额外的开销,会降低性能。
与快照不同,动态集不用光标库维持的缓冲区来存放记录。实际上,动态集是不使用光标库的,因为光标库会屏蔽掉一些支持动态集的底层驱动程序功能。动态集是一种键集驱动光标(Keyset-Driven Cursor),当打开一个动态集时,驱动程序保存记录集中每个记录的键。只要光标在动态集中滚动,驱动程序就会通过键来从数据源中检取当前记录,从而保证选取的记录与数据源同步。
从上面的分析中可以看出,快照和动态集有一个共同的特点,那就是在建立记录集后,记录集中的成员就已经确定了。这就是为什么两种记录集都不能反映别的用户添加记录的原因。
2. 域数据成员与数据交换
CRecordset类代表一个记录集。用户一般需要用ClassWizard创建一个CRecordset的派生类。ClassWizard可以为派生的记录集类创建一批数据成员,这些数据成员与记录的各字段相对应,被称为字段数据成员或域数据成员。例如,对于表1所示的将在后面例子中使用的数据库表,ClassWizard会在派生类中加入6个域数据成员,如清单1所示。可以看出域数据成员与表中的字段名字类似,且类型匹配。
(表1)stdreg32.mdb中的Section表
CourseID (Text) |
SectionNo (Text) |
InstructorID (Text) |
RoomNo (Text) |
Schedule (Text) |
Capacity (int) |
MATH101 |
1 |
KLAUSENJ |
KEN-12 |
MWF10-11 |
40 |
MATH101 |
2 |
ROGERSN |
WIL-1088 |
TTH3:30-5 |
15 |
MATH201 |
1 |
ROGERSN |
WIL-1034 |
MWF2-3 |
20 |
MATH201 |
2 |
SMITHJ |
WIL-1054 |
MWF3-4 |
25 |
MATH202 |
1 |
KLA |
WIL-1054 |
MWF9-10 |
20 |
MATH202 |
2 |
ROGERSN |
KEN-12 |
TTH9:30-11 |
15 |
MATH202 |
3 |
KLAUSENJ |
WIL-2033 |
TTH3-4:30 |
15 |
(清单1)派生类中的域数据成员
class CSectionSet : public CRecordset
{
public:
……
//{ {AFX_FIELD(CSectionSet, CRecordset)
CString m_CourseID;
CString m_SectionNo;
CString m_InstructorID;
CString m_RoomNo;
CString m_Schedule;
int m_Capacity;
//}}AFX_FIELD
……
};
域数据成员用来保存某条记录的各个字段,它们是程序与记录之间的缓冲区。域数据成员代表当前记录,当在记录集中滚动到某一记录时,框架自动地把记录的各个字段拷贝到记录集对象的域数据成员中。当用户要修改当前记录或增加新记录时,程序先将各字段的新值放入域数据成员中,然后调用相应的CRecordset成员函数把域数据成员设置到数据源中。
不难看出,在记录集与数据源之间有一个数据交换问题。CRecordset类使用“记录域交换”(Record Field Exchange,缩写为RFX)机制自动地在域数据成员和数据源之间交换数据。RFX机制与对话数据交换(DDX)类似。