本单元将对db4o如何处理复杂的结构化对象进行详细的介绍,主要内容有:(1)、存储结构化对象;(2)、db4o对于结构化对象的查询操作。另外,有感按照db4o开发文档原文翻译是一件十分费时的工作,为了尽量保证与原文内容上的一致性,会舍去不少东西从而使本笔记的可读性有所降低,为此从下一篇开始采取对原文地概览的方式,然后再增加一个小案例进行实践以此综合运用db4o所提供了各项功能。
摘要:
本单元将对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); |