三、CRecordset类
1、IsBOF与IsEOF
(1)IsBOF
如果记录集没有记录,或已经向前游动到第一个记录之前,则返回非零;否则返回0。详细说明如下:
1)访问Open函数之后,如果记录集没有任何记录,IsBOF返回非零。当你打开一个至少包含一个记录的记录集,第一个记录是当前记录,此时IsBOF返回0。
2)如果第一个记录是当前记录并且你访问MovePrev,之后IsBOF会返回非零值。如果IsBOF返回非零值并且访问MovePrev函数,会报错。
3)如果IsBOF返回非零值,说明当前记录没有定义,任何请求当前记录的动作将会导致错误。
(2)IsEOF
如果记录集没有记录,或已经滚动到最后一条纪录之后,则返回非零。否则,返回0。
if (m_test.IsOpen()) m_test.Close(); m_test.Open(); //如果记录集为空,返回 if (m_test.IsBOF()) return FALSE; //如果不是最后一个记录的下一个位置,就向下移动一个记录 while (!m_test.IsEOF) { m_test.MoveNext(); }
2、快照(Snapshot) 和动态集(Dynaset)
在多任务操作系统或网络环境中,多个用户可以共享同一个数据源。共享数据的一个主要问题是如何协调各个用户对数据源的修改。例如,当某一个应用改变了数据源中的记录时,别的连接至该数据源的应用应该如何处理。对于这个问题,基于MFC的ODBC应用程序可以采取几种不同的处理办法,这将由程序采用哪种记录集决定。
记录集主要分为快照(Snapshot) 和动态集(Dynaset)两种,CRecordset类对这两者都支持。这两种记录集的不同表现在它们对别的应用改变数据源记录采取了不同的处理方法。
(1)快照(Snapshot)
快照型记录集提供了对数据的静态视。当别的用户改变了记录时(包括修改、添加和删除),快照中的记录不受影响,也就是说,快照不反映别的用户对数据源记录的改变,直到调用了CRecordset::Requery重新查询后,快照才会反映变化。需要指出的是,快照的这种静态特性是相对于别的用户而言的,它会正确反映由本身用户对记录的修改和删除,但对于新添加的记录直到调用Requery后才能反映到快照中。
(2)动态集(Dynaset)
动态集提供了数据的动态视。当别的用户修改或删除了记录集中的记录时,会在动态集中反映出来:当滚动到修改过的记录时对其所作的修改会立即反映到动态集中,当记录被删除时,MFC代码会跳过记录集中的删除部分。对于其它用户添加的记录,直到调用Requery时,才会在动态集中反映出来。本身应用程序对记录的修改、添加和删除会反映在动态集中。当数据必须是动态的时侯,使用动态集是最适合的。例如,在一个火车票联网售票系统中,显然应该用动态集随时反映出共享数据的变化。
(3)光标机制
在记录集中滚动,需要有一个标志来指明滚动后的位置(当前位置)。ODBC驱动程序会维护一个光标,用来跟踪记录集的当前记录,可以把光标理解成跟踪记录集位置的一种机制。
光标库(Cursor Library)是处于ODBC驱动程序管理器和驱动程序之间的动态链接库(ODBCCR32.DLL)。光标库的主要功能是支持快照以及为底层驱动程序提供双向滚动能力,高层次的驱动程序不需要光标库,因为它们是可滚动的。光标库管理快照记录的缓冲区,该缓冲区反映本程序对记录的修改和删除,但不反映其它用户对记录的改变,由此可见,快照实际上相当于当前的光标库缓冲区。
快照是一种静态光标(Static Cursor)。静态光标直到滚动到某个记录才能取得该记录的数据。因此,要保证所有的记录都被快照,可以先滚动到记录集的末尾,然后再滚动到感兴趣的第一个记录上。这样做的缺点是滚动到末尾需要额外的开销,会降低性能。
与快照不同,动态集不用光标库维持的缓冲区来存放记录。实际上,动态集是不使用光标库的,因为光标库会屏蔽掉一些支持动态集的底层驱动程序功能。动态集是一种键集驱动光标(Keyset-Driven Cursor),当打开一个动态集时,驱动程序保存记录集中每个记录的键。只要光标在动态集中滚动,驱动程序就会通过键来从数据源中检取当前记录,从而保证选取的记录与数据源同步。
从上面的分析中可以看出,快照和动态集有一个共同的特点,那就是在建立记录集后,记录集中的成员就已经确定了。这就是为什么两种记录集都不能反映别的用户添加记录的原因。
3、Open与Requery
CRecordSet的Open()和Requery()成员函数可以实现记录查询。详细说明如下:
(1)使用CRecordSet的类对象之前,必须使用CRecordSet的成员函数Open()来获得有效的记录集。一旦使用过Open()函数,再次查询时使用Requery()函数就可以了。
(2)调用Open()函数时,如果已经将一个打开的CDatabase对象指针传递给CRecordSet类对象的m_pDatabase成员变量,那么,CRecordSet类对象将使用该数据库对象建立ODBC连接;否则,如果m_pDatabase为空指针,对象就需要就新建一个CDatabase类对象并使其与缺省的数据源相连,然后进行CRecordSet类对象的初始化。缺省数据源由GetDefaultConnect()函数获得。
(3)也可以提供所需要的SQL语句,并以它来调用CRecordSet::Open()函数,例如:
//strSQL为SQL语句 m_test.Open(AFX_DB_USE_DEFAULT_TYPE, strSQL);
(4)如果Open没有指定参数,程序使用缺省的SQL语句,即对在GetDefaultSQL()函数中指定的SQL语句进行操作。例如:
CString CHistorySet::GetDefaultSQL() { return _T("[History]"); }
GetDefaultSQL()函数返回的表名,对应的缺省操作是SELECT语句,即:SELECT *FROM History。