3、使用行集和游标
在Symbian系统的DBMS中,使用行集可以对数据库中的数据进行查找,恢复与修改操作。
关于行集有一点需要牢记,即列集所包括的并不是数据本身,其容纳的非永存性元素只是对数据库中真实数据行的索引进行解析。
3.1 行集定义
列集的API包含三个主要概念:
? ·行集基类(RDbRowSet)?——一个抽象类可以提供导航,行恢复以及数据的更新。数据源由两个具体的操作定义。
? ·表行集(RDbTable)——提供表的完全视图。
? ·SQL 视图(RDbView)——提供表的一个视图。该视图依赖于建立视图的SQL查询。其可能包含数据的一部分和表的一部份列。
3.1.1 行集基类
下列功能由Symbian 系统下,DBMS的行集操作提供:
? ·行寻找与匹配
? ·从数据库中回复数据
? ·更新或插入行
? ·使用游标对行集进行导航
? ·使用行集获得行记录的架构
? ·在行中解析与设定列
通过使用RDbRowSet,一个基类可以对所有的行集类型进行定义。行集的具体类型要从类中获取。
为了获取数据,数据库应用程序使用一个行集于当前行记录在的集合中维持一个游标。行集提供一个抽象借口和两个具体类型:表行集与SQL视图。
3.1.2 表行集
表行集将表的所有行和所有列视作一个行集。在行集中可以使用索引,从而从表中迅速获得主键基准的列。若没有使用索引,检索出的行将是无序的。表行集被封装在RDBTab类中。
当必须查看全表结构或需要以某种顺序查看表中数据时,表行集时非常有用的。如果想查找一个独立且唯一的行,表行集优于SQL的视图。(参见3.3节,“使用索引获取数据”,可以了解到使用索引如何达到以上所说的效果)然而,在达到多数情况,SQL更优。
3.1.3 SQL视图
使用RDbView类可以对行集进行SQL查询。任何SQL查询都封装在TdbQuery中。一个SQL视图是一个行集,其由数据库上的SQL查询语句实现且由一个单独的表对其约束。RDbView类的Prepare方法可解析SQL并且可确定如何获取数据的值。在缺省状态下,必须通过评估视图的值实现游标导航。
由于评价过程是很耗费时间的,一个预估值窗TDbWindow可能在预备阶段使用,其能令行集进行依次评估并进行快速导航。完全的评估可能需要很长时间,最好是对数据库进行分步评估。
对于巨型行集,TDbWindow可以在平衡内存耗费(若视图存储完全的行集耗费将是巨大的)与速度(若行集被每个游标导航,速度将最慢)。行集可通过定义一个有限(或部分)的,大小适中的预评估窗来获取这种平衡。一个部分估值窗同样可用于获得本地导航SQL 结果集的部分视图。
下列代码组织了一个使用SQL查找语句的视图:
...
private: // 数据成员
RDbStoreDatabase iBookDb;
...
_LIT(KViewSql,"SELECT Author, Title FROM Books"
RDbView view;
User::LeaveIfError(
view.Prepare(iBookDb, TDbQuery(KViewSql),
view.EReadOnly));
CleanupClosePushL(view);
User::LeaveIfError(view.EvaluateAll());
for (view.FirstL(); view.AtRow(); view.NextL())
{
view.GetL(); // 获取当前行的副本
... // 对行进行操作
}
CleanupStack::PopAndDestroy(); // 这样同样可关闭视图
3.2 游标
一个游标可以对行集中的所有有效行进行导航。有效行依赖于行集是如何生成的,特别是行集是否是使用评估窗的SQL视图
3.2.1 游标状态
在大多数普通情况下,游标保存来自行集的,从属于行的值。然而,游标还需要保存其他一些状态。
一个游标可以保存“起始”或“结束”状态。起初,游标进行重置,游标定位于开始端。其初始位置指向第一行的前一行,结束位置指向最后一行的下一行。对于一个空集来说,其仍有指向数据集尾的游标,在这种情况下,从起始位置对第一行进行导航和对最后一行进行导航是等价的,游标在起始状态时定位。在对集合的最后一行进行导航时,执行过程是相似的。
当对一行进行更新或插入操作时,游标有一个状态阻止导航,直到更新或插入操作完成。
删除当前行后,游标不发生变化并保存由于删除操作所而生成的无效值。当导航至下一行,前一行或特殊行时,游标将移动至指定行或者在还有行的情况下,指向起始或结束位置,删除行集值时,行集中的值将被从行集中移除。
3.3 通过索引获得数据
可以通过使用SQL视图或RDbTable行集对象,生成一个索引来获取数据。
RdbTable类提供了一个简单的SeeKL方法来快速查找行。其使用TDbSeekKey来获取当前存在的第一行值。当使用已知唯一索引键快速获得一行值时,SeeKL方法非常有效。若需要更多复杂的查找操作,SQL视图与RdbRowSet基类可以提供丰富的解决办法。
下列代码使用RDbTable和一个索引项来查找行的首次匹配。索引在2.3.3节定义,“索引键。”
...
_LIT(KBooksTable, "Books");
_LIT(KBooksIndexName,"BooksIndex");
...
private: // 数据成员
RDbStoreDatabase iBookDb;
...
void CBookDb::GetABookFastL(const TDesC& aTitle, TDes& aResult)
{
RDbTable rowset;
RDbTable table;
TDbSeekKey seekKey(aTitle); // 初始化单列查询值
// Open the ‘Books’ table. Specify what index is used.
// 打开Books表,实例化使用的索引
User::LeaveIfError(
table.Open(iBookDb, KBooksTable, rowset.EReadOnly));
CleanupClosePushL(table); // 记得弹出与关闭表
User::LeaveIfError(table.SetIndex(KBooksIndexName));
if( rowset.SeekL(seekKey) ) // SeeKL需要的键是一个集合
{
// 游标被设定用于查找列,关于游标的相关操作。
rowset.GetL();
...
}
else
{
// 找不到值
}
...
// 将表从清洁栈中弹出,将清洁栈关闭
CleanupStack::PopAndDestroy();
索引数据类型必须匹配目标类型,即Tint匹配ColIntnn,等等。一个TdbSeekKey对象使用需求匹配值(aTitle)索引来创建。举个例子,有一个已知索引,但其在查询表时,必须以下列格式使用才行:
CDbNames* idxs = iBookDb.IndexNamesL(KBooksTable);
在试图查找表前,为表设定索引是非常重要的。最终,SeekL()尝试去匹配值。如果键值被匹配,那么游标则被设定到指定位置。一个后续方法GetL()将获得数据以备进一步操作。