db4o学习笔记(四)、db4o查询详解续

摘要:

  在上一单元中对db4o中采用QBE及NQ对数据库进行查询作了详细的讨论,今天将就其提供的底层查询接口SODA进行介绍,内容包括(1)、SODA查询对象的创建;(2)、约束条件的使用及约束表达式;(3)、对于三种查询方式各自适合的应用场景进行了简要的介绍。

  正文:

  SODAdb4o提供的底层查询接口,允许开发人员直接操作查询表达式树中的节点,它采用字符串标识对象数据成员,但是这种方式既不是类型安全也不在编译时进行检查并且写起来十分冗长。

  对大多数应用程序来说使用NQ将是很好的选择。

  SODA也有其它两种查询不可比拟的优势,那就是使用你的应用程序能够动态生成查询,这也是部分应用开发所需的。

  3.3.1、简单查询

  让我们以上一单元中熟悉的QBE查询转换为SODA为例开始吧,通过ObjectContainer#.query()方法并为其提供约束条件实例来获取一个新的Query对象,在查询所有车手的示例中,对于查询的约束为Pilot类对象。

1
2
3
4
5
[retrieveAllPilots]
Query query = db.Query();
query.Constrain(typeof(Pilot));
ObjectSet result = query.Execute();
ListResult(result);

  基本上来说,我们只是使用描述对象的元数据来替换先前提供了实例原型来获取想要查询的资料,系统将会构建一个包含查询节点及约束的表达式树,查询节点用于容纳查询结果的候选对象,约束条件决定了哪些应用包含/排队在查询结果中。

  第一个简单的表达式树(图解)看上去会是这样的。

  我们向数据库中询问所有类型为Pilot的候选对象并将其聚集到我们的查询结果中。

  为了通过车手名字进行查询,我们需要扩展上述约束条使其包含待查询对象的”name”字段的相应字符串。

1
2
3
4
5
6
[retrievePilotByName]
Query query = db.Query();
query.Constrain(typeof(Pilot));
query.Descend("_name").Constrain("Michael Schumacher");
ObjectSet result = query.Execute();
ListResult(result);

  使用”descend”的目的是将附加的约束条件增加到表达式树(图解)中以判断我们的候选对象,就像上述原型实例一样。

  因此,满足这个查询的候选对象需要是Pilot类型并且其数据成员”name”必须与给出的字符串相匹配才能加入到结果集中。

  需要引起注意的是类约束并不是必需的,如果让其为空将会查询所有拥有”name”成员为给定值的对象,大多数情况下这似乎并不我们所希望的结果。

  通过车手积分进行精确的查询如下:

  

1
2
3
4
5
6
[retrievePilotByExactPoints]
Query query = db.Query();
query.Constrain(typeof(Pilot));
query.Descend("_points").Constrain(100);
ObjectSet result = query.Execute();
ListResult(result);

  3.3.2、高级查询

  现在我们并不希望通过对象成员的精确匹配来进行查询了,而是更希望通过值域或者不包含给定成员值的对象等,这些约束接口都提供了支持。

  首先,来看看查询不是”Michael Schumacher”的工作是如何完成的?

1
2
3
4
5
6
[retrieveByNegation]
Query query = db.Query();
query.Constrain(typeof(Pilot));
query.Descend("_name").Constrain("Michael Schumacher").Not();
ObjectSet result = query.Execute();
ListResult(result);

  如果查询表达式的结果为假将会阻止后续的布尔运算操作。

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[retrieveByConjunction]
Query query = db.Query();
query.Constrain(typeof(Pilot));
Constraint constr = query.Descend("_name")
.Constrain("Michael Schumacher");
query.Descend("_points")
.Constrain(99).And(constr);
ObjectSet result = query.Execute();
ListResult(result);
/// ---
[retrieveByDisjunction]
Query query = db.Query();
query.Constrain(typeof(Pilot));
Constraint constr = query.Descend("_name")
.Constrain("Michael Schumacher");
query.Descend("_points")
.Constrain(99).Or(constr);
ObjectSet result = query.Execute();
ListResult(result);

  也可以在查询中对给定值作比较运算。

1
2
3
4
5
6
7
[retrieveByComparison]
Query query = db.Query();
query.Constrain(typeof(Pilot));
query.Descend("_points")
.Constrain(99).Greater();
ObjectSet result = query.Execute();
ListResult(result);

  查询接口还允许对数据成员的默认进行查询及对查询结果进行排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[retrieveByDefaultFieldValue]
Pilot somebody = new Pilot("Somebody else", 0);
db.Set(somebody);
Query query = db.Query();
query.Constrain(typeof(Pilot));
query.Descend("_points").Constrain(0);
ObjectSet result = query.Execute();
ListResult(result);
db.Delete(somebody);
/// 以下是对查询结果进行排序
[retrieveSorted]
Query query = db.Query();
query.Constrain(typeof(Pilot));
query.Descend("_name").OrderAscending();
ObjectSet result = query.Execute();
ListResult(result);
query.Descend("_name").OrderDescending();
result = query.Execute();
ListResult(result);

  上述所有条件都可以进行任意的组合以完成更复杂的操作,当然还是会存在其难于完成的任务,不用担心db4o早就想到这一点啦这可以通过db4o提供的求值运算(表达式)来完成,求值运算将会在后续的章节中进行讨论。

  3.3.3、小结

  现在对db4o数据库的查询工作我们可以通过其提供的三种方式中的任意一种来完成,它们分别是:(1)、QBE;(2)、NQ;(3)、SODA  对于何时采用哪种方式进行查询,我们的建议是:

  1)、NQ作为db4o主要的查询接口将是我们不二的首选;

  2)、当前版本中对NQ查询的优化操作总是以SODA方式来执行的,因此SODA可以作为系统优化的一种途径,同时它总是用来在运行时动态的生成查询。

  3)、QBE对于初学者来说将是很好的选择,当然它在功能上会有些限制,如果你喜欢的话有时对的应用还是很适合的

  当然综合运用这几种方式会更好。

  在完成练习后我们知道了db4o所提供的几种查询方式,但是我们的领域模型并不复杂才仅公一个类而矣,在下一章中将对db4o中处理复合对象进行讨论。

完整代码

你可能感兴趣的:(学习笔记)