在上一单元中对db4o中采用QBE及NQ对数据库进行查询作了详细的讨论,今天将就其提供的底层查询接口SODA进行介绍,内容包括(1)、SODA查询对象的创建;(2)、约束条件的使用及约束表达式;(3)、对于三种查询方式各自适合的应用场景进行了简要的介绍。
正文:
SODA是db4o提供的底层查询接口,允许开发人员直接操作查询表达式树中的节点,它采用字符串标识对象数据成员,但是这种方式既不是类型安全也不在编译时进行检查并且写起来十分冗长。
对大多数应用程序来说使用NQ将是很好的选择。
而SODA也有其它两种查询不可比拟的优势,那就是使用你的应用程序能够动态生成查询,这也是部分应用开发所需的。
3.3.1、简单查询
让我们以上一单元中熟悉的QBE查询转换为SODA为例开始吧,通过ObjectContainer的#.query()方法并为其提供约束条件实例来获取一个新的Query对象,在查询所有车手的示例中,对于查询的约束为Pilot类对象。
1 | [retrieveAllPilots] |
基本上来说,我们只是使用描述对象的元数据来替换先前提供了实例原型来获取想要查询的资料,系统将会构建一个包含查询节点及约束的表达式树,查询节点用于容纳查询结果的候选对象,约束条件决定了哪些应用包含/排队在查询结果中。
第一个简单的表达式树(图解)看上去会是这样的。
我们向数据库中询问所有类型为Pilot的候选对象并将其聚集到我们的查询结果中。
为了通过车手名字进行查询,我们需要扩展上述约束条使其包含待查询对象的”name”字段的相应字符串。
1 | [retrievePilotByName] |
使用”descend”的目的是将附加的约束条件增加到表达式树(图解)中以判断我们的候选对象,就像上述原型实例一样。
因此,满足这个查询的候选对象需要是Pilot类型并且其数据成员”name”必须与给出的字符串相匹配才能加入到结果集中。
需要引起注意的是类约束并不是必需的,如果让其为空将会查询所有拥有”name”成员为给定值的对象,大多数情况下这似乎并不我们所希望的结果。
通过车手积分进行精确的查询如下:
1 | [retrievePilotByExactPoints] |
3.3.2、高级查询
现在我们并不希望通过对象成员的精确匹配来进行查询了,而是更希望通过值域或者不包含给定成员值的对象等,这些约束接口都提供了支持。
首先,来看看查询不是”Michael Schumacher”的工作是如何完成的?
1 | [retrieveByNegation] |
如果查询表达式的结果为假将会阻止后续的布尔运算操作。
1 | [retrieveByConjunction] |
也可以在查询中对给定值作比较运算。
1 | [retrieveByComparison] |
查询接口还允许对数据成员的默认进行查询及对查询结果进行排序。
1 | [retrieveByDefaultFieldValue] |
上述所有条件都可以进行任意的组合以完成更复杂的操作,当然还是会存在其难于完成的任务,不用担心db4o早就想到这一点啦这可以通过db4o提供的求值运算(表达式)来完成,求值运算将会在后续的章节中进行讨论。
3.3.3、小结
现在对db4o数据库的查询工作我们可以通过其提供的三种方式中的任意一种来完成,它们分别是:(1)、QBE;(2)、NQ;(3)、SODA。 对于何时采用哪种方式进行查询,我们的建议是:
(1)、NQ作为db4o主要的查询接口将是我们不二的首选;
(2)、当前版本中对NQ查询的优化操作总是以SODA方式来执行的,因此SODA可以作为系统优化的一种途径,同时它总是用来在运行时动态的生成查询。
(3)、QBE对于初学者来说将是很好的选择,当然它在功能上会有些限制,如果你喜欢的话有时对的应用还是很适合的
当然综合运用这几种方式会更好。
在完成练习后我们知道了db4o所提供的几种查询方式,但是我们的领域模型并不复杂才仅公一个类而矣,在下一章中将对db4o中处理复合对象进行讨论。
1using System;
2using com.db4o;
3using com.db4o.query;
4using com.db4o.f1;
5namespace com.db4o.f1.chapter1
6{
7 public class QueryExample : Util
8 {
9 public static void Main(string[] args)
10 {
11 ObjectContainer db = Db4o.OpenFile(Util.YapFileName);
12 try
13 {
14 StoreFirstPilot(db);
15 StoreSecondPilot(db);
16 RetrieveAllPilots(db);
17 RetrievePilotByName(db);
18 RetrievePilotByExactPoints(db);
19 RetrieveByNegation(db);
20 RetrieveByConjunction(db);
21 RetrieveByDisjunction(db);
22 RetrieveByComparison(db);
23 RetrieveByDefaultFieldValue(db);
24 RetrieveSorted(db);
25 ClearDatabase(db);
26 }
27 finally
28 {
29 db.Close();
30 }
31 }
32
33 public static void StoreFirstPilot(ObjectContainer db)
34 {
35 Pilot pilot1 = new Pilot("Michael Schumacher", 100);
36 db.Set(pilot1);
37 Console.WriteLine("Stored {0}", pilot1);
38 }
39
40 public static void StoreSecondPilot(ObjectContainer db)
41 {
42 Pilot pilot2 = new Pilot("Rubens Barrichello", 99);
43 db.Set(pilot2);
44 Console.WriteLine("Stored {0}", pilot2);
45 }
46
47 public static void RetrieveAllPilots(ObjectContainer db)
48 {
49 Query query = db.Query();
50 query.Constrain(typeof(Pilot));
51 ObjectSet result = query.Execute();
52 ListResult(result);
53 }
54
55 public static void RetrievePilotByName(ObjectContainer db)
56 {
57 Query query = db.Query();
58 query.Constrain(typeof(Pilot));
59 query.Descend("_name").Constrain("Michael Schumacher");
60 ObjectSet result = query.Execute();
61 ListResult(result);
62 }
63
64 public static void RetrievePilotByExactPoints(ObjectContainer db)
65 {
66 Query query = db.Query();
67 query.Constrain(typeof(Pilot));
68 query.Descend("_points").Constrain(100);
69 ObjectSet result = query.Execute();
70 ListResult(result);
71 }
72
73 public static void RetrieveByNegation(ObjectContainer db)
74 {
75 Query query = db.Query();
76 query.Constrain(typeof(Pilot));
77 query.Descend("_name").Constrain("Michael Schumacher").Not();
78 ObjectSet result = query.Execute();
79 ListResult(result);
80 }
81
82 public static void RetrieveByConjunction(ObjectContainer db)
83 {
84 Query query = db.Query();
85 query.Constrain(typeof(Pilot));
86 Constraint constr = query.Descend("_name")
87 .Constrain("Michael Schumacher");
88 query.Descend("_points")
89 .Constrain(99).And(constr);
90 ObjectSet result = query.Execute();
91 ListResult(result);
92 }
93
94 public static void RetrieveByDisjunction(ObjectContainer db)
95 {
96 Query query = db.Query();
97 query.Constrain(typeof(Pilot));
98 Constraint constr = query.Descend("_name")
99 .Constrain("Michael Schumacher");
100 query.Descend("_points")
101 .Constrain(99).Or(constr);
102 ObjectSet result = query.Execute();
103 ListResult(result);
104 }
105
106 public static void RetrieveByComparison(ObjectContainer db)
107 {
108 Query query = db.Query();
109 query.Constrain(typeof(Pilot));
110 query.Descend("_points")
111 .Constrain(99).Greater();
112 ObjectSet result = query.Execute();
113 ListResult(result);
114 }
115
116 public static void RetrieveByDefaultFieldValue(ObjectContainer db)
117 {
118 Pilot somebody = new Pilot("Somebody else", 0);
119 db.Set(somebody);
120 Query query = db.Query();
121 query.Constrain(typeof(Pilot));
122 query.Descend("_points").Constrain(0);
123 ObjectSet result = query.Execute();
124 ListResult(result);
125 db.Delete(somebody);
126 }
127
128 public static void RetrieveSorted(ObjectContainer db)
129 {
130 Query query = db.Query();
131 query.Constrain(typeof(Pilot));
132 query.Descend("_name").OrderAscending();
133 ObjectSet result = query.Execute();
134 ListResult(result);
135 query.Descend("_name").OrderDescending();
136 result = query.Execute();
137 ListResult(result);
138 }
139
140 public static void ClearDatabase(ObjectContainer db)
141 {
142 ObjectSet result = db.Get(typeof(Pilot));
143 foreach (object item in result)
144 {
145 db.Delete(item);
146 }
147 }
148 }
149}
150