摘要:
本单元将对db4o如何处理复杂的结构化对象进行详细的介绍,主要内容有:(1)、存储结构化对象;(2)、db4o对于结构化对象的查询操作。另外,有感按照db4o开发文档原文翻译是一件十分费时的工作,为了尽量保证与原文内容上的一致性,会舍去不少东西从而使本笔记的可读性有所降低,为此从下一篇开始采取对原文地概览的方式,然后再增加一个小案例进行实践以此综合运用db4o所提供了各项功能。
正文:
是时候对我们的业务模型进行扩展了,看看db4o是如何处理对象之间相互关系的,我们给车手添加一个交通工具。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
namespace com.db4o.f1.chapter2
{
public class Car
{
string _model;
Pilot _pilot; public Car(string model)
{
_model = model;
_pilot = null;
}
public Pilot Pilot
{
get
{
return _pilot;
}
set
{
_pilot = value;
}
}
public string Model
{
get
{
return _model;
}
}
override public string ToString()
{
return string.Format("{0}[{1}]", _model, _pilot);
}
}
}
4.1、存储结构化对象
为了存储含有车手信息的Car对象,只需在顶层对象(Car)调用Set()方法即可,其车手对象也会自动的进行存储。
1
2
3
4
5
[storeFirstCar]
Car car1 = new Car("Ferrari");
Pilot pilot1 = new Pilot("Michael Schumacher", 100);
car1.Pilot = pilot1;
db.Set(car1);
当然,也存在其它可选的方法,这次在存储Car对象时我们先明确的存储车手信息,再处理Car对象,这和上面的方式没有什么区别。
1
2
3
4
5
6
[storeSecondCar]
Pilot pilot2 = new Pilot("Rubens Barrichello", 99);
db.Set(pilot2);
Car car2 = new Car("BMW");
car2.Pilot = pilot2;
db.Set(car2);
4.2、加载结构化对象
4.2.1、QBE
为加载所有的车辆对象,咱依然只需提供一个原型对象。
1
2
3
4
[retrieveAllCarsQBE]
Car proto = new Car(null);
ObjectSet result = db.Get(proto);
ListResult(result);
我们也可以直接查询所有的车手对象。
1
2
3
4
[retrieveAllPilotsQBE]
Pilot proto = new Pilot(null, 0);
ObjectSet result = db.Get(proto);
ListResult(result);
现在将原型对象初始化”Rubens Barrichello”驾驶的车辆。
1
2
3
4
5
6
[retrieveCarByPilotQBE]
Pilot pilotproto = new Pilot("Rubens Barrichello",0);
Car carproto = new Car(null);
carproto.Pilot = pilotproto;
ObjectSet result = db.Get(carproto);
ListResult(result);
怎样通过车辆信息加载车手对象呢?如果我们知道车辆信息就不必像上面这样,直接存取车手对象即可。
4.2.2、NQ
使用NQ查询聚合层次较深的对象也很简单,就像平时处理其它对象一样。来看看通过指定姓名的车手来查询车辆对象的查询。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class RetrieveCarsByPilotNamePredicate : Predicate
{
readonly string _pilotName; public RetrieveCarsByPilotNamePredicate(string pilotName)
{
_pilotName = pilotName;
}
public bool Match(Car candidate)
{
return candidate.Pilot.Name == _pilotName;
}
}
通过车手名字查询车辆信息:
1
2
3
4
[retrieveCarsByPilotNameNative]
string pilotName = "Rubens Barrichello";
ObjectSet results = db.Query(new RetrieveCarsByPilotNamePredicate(pilotName));
ListResult(results);
.NET 2.0语法甚至更简单:
1
2
3
4
5
[retrieveCarsByPilotNameNative]
string pilotName = "Rubens Barrichello";
List<Car> results = db.Query<Car>(delegate(Car car) {
return car.Pilot.Name == pilotName; });
listResults(results);
4.2.3、SODA
为了使用SODA执行同样的查询我们需要向约束条件中添加两个层次的条件。
1
2
3
4
5
6
7
[retrieveCarByPilotNameQuery]
Query query = db.Query();
query.Constrain(typeof(Car));
query.Descend("_pilot").Descend("_name")
.Constrain("Rubens Barrichello");
ObjectSet result = query.Execute();
ListResult(result);
也可以通过使用pilot字段的原型对象来达到同样的目的。
1
2
3
4
5
6
7
[retrieveCarByPilotProtoQuery]
Query query = db.Query();
query.Constrain(typeof(Car));
Pilot proto = new Pilot("Rubens Barrichello", 0);
query.Descend("_pilot").Constrain(proto);
ObjectSet result = query.Execute();
ListResult(result);
再看看采用descend添加约束的方法提供另外的查询示例,从查询的根节点我可以从多条路径添加约束,实际上从子节点向下添加约束与从父节点向下添加约束是一样的。由此可知查询引擎能从任意方向来引用我们的对象到其真实的关系。以下便是查询一个驾驶着拥有法拉利引擎汽车的车手对象的示例:
1
2
3
4
5
6
7
[retrievePilotByCarModelQuery]
Query carQuery = db.Query();
carQuery.Constrain(typeof(Car));
carQuery.Descend("_model").Constrain("Ferrari");
Query pilotQuery = carQuery.Descend("_pilot");
ObjectSet result = pilotQuery.Execute();
ListResult(result);
