7. 深层探险
我们已经看到db4o是如何处理对象关系的了,但是我们使用的例子比起现实世界来都过于简单。特别是,我们没有看到db4o在循环结构中如何存储。现在我们来仿真这样的一个结构:隐性的将之前的history list替换为sensorReadout类的对象。

Sensor Readout
using System;
namespace Db4objects.Db4o.Tutorial.F1.Chapter5


{
public abstract class SensorReadout

{
DateTime _time;
Car _car;
string _description;
SensorReadout _next;
protected SensorReadout(DateTime time, Car car, string description)

{
_time = time;
_car = car;
_description = description;
_next = null;
}
public Car Car

{
get

{
return _car;
}
}
public DateTime Time

{
get

{
return _time;
}
}
public SensorReadout Next

{
get

{
return _next;
}
}
public void Append(SensorReadout sensorReadout)

{
if (_next == null)

{
_next = sensorReadout;
}
else

{
_next.Append(sensorReadout);
}
}
public int CountElements()

{
return (_next == null ? 1 : _next.CountElements() + 1);
}
override public string ToString()

{
return string.Format("{0} : {1} : {2}", _car, _time, _description);
}
}
}

car只和 'head' sensor readout 有关系:

new car
using System;
namespace Db4objects.Db4o.Tutorial.F1.Chapter5


{
public class Car

{
string _model;
Pilot _pilot;
SensorReadout _history;
public Car(string model)

{
_model = model;
_pilot = null;
_history = null;
}
public Pilot Pilot

{
get

{
return _pilot;
}
set

{
_pilot = value;
}
}
public string Model

{
get

{
return _model;
}
}
public SensorReadout GetHistory()

{
return _history;
}
public void Snapshot()

{
AppendToHistory(new TemperatureSensorReadout(
DateTime.Now, this, "oil", PollOilTemperature()));
AppendToHistory(new TemperatureSensorReadout(
DateTime.Now, this, "water", PollWaterTemperature()));
AppendToHistory(new PressureSensorReadout(
DateTime.Now, this, "oil", PollOilPressure()));
}
protected double PollOilTemperature()

{
return 0.1*CountHistoryElements();
}
protected double PollWaterTemperature()

{
return 0.2*CountHistoryElements();
}
protected double PollOilPressure()

{
return 0.3*CountHistoryElements();
}
override public string ToString()

{
return string.Format("{0}[{1}]/{2}", _model, _pilot, CountHistoryElements());
}
private int CountHistoryElements()

{
return (_history == null ? 0 : _history.CountElements());
}
private void AppendToHistory(SensorReadout readout)

{
if (_history == null)

{
_history = readout;
}
else

{
_history.Append(readout);
}
}
}
}

7.1. 存储和更新
这里没有不同:
// storeCar
Pilot pilot = new Pilot("Rubens Barrichello", 99);
Car car = new Car("BMW");
car.Pilot = pilot;
db.Set(car);
现在建立一个 sensor readout 链.。首先设置更新深度:
// setCascadeOnUpdate
Db4oFactory.Configure().ObjectClass(typeof(Car)).CascadeOnUpdate(true);
收集一些sensor readouts.
// takeManySnapshots
IObjectSet result = db.Get(typeof(Car));
Car car = (Car)result.Next();
for (int i=0; i<5; i++)


{
car.Snapshot();
}
db.Set(car);
7.2. 检索
现在已经有了一个复杂的结构,我们来检索一下:
首先,来验证是否有了很多的snapshots.:
// retrieveAllSnapshots
IObjectSet result = db.Get(typeof(SensorReadout));
while (result.HasNext())


{
Console.WriteLine(result.Next());
}
这些readouts 都是属于一个相联系的链, 所有我们需要通过对结构的检索来访问他们:
// retrieveSnapshotsSequentially
IObjectSet result = db.Get(typeof(Car));
Car car = (Car)result.Next();
SensorReadout readout = car.GetHistory();
while (readout != null)


{
Console.WriteLine(readout);
readout = readout.Next;
}
看看,发生了什么?
7.2.1. 激活深度
这只是更新深度的另外一方面问题。.
当你从数据库提取数据后,db4o并不会跟踪引用。所以,获取“完整”的对象需要你自己去检索。如果不是这样的话,当你有很多个对象引用的时候,只想执行一个简单的检索的时候,db4o就要把整个数据库翻一个底朝天,然后把这么多数据一下子读入内存。.
在多数情况下,这样做是不好的。所以db4o提供了一个机制,可以完全按照客户的需要来检索对象。这个机制叫做激活深度,和更新深度非常象。
默认的激活深度为5,所以,上面的代码得到了5个引用。
激活深度是可以设置的。这就可以实现我们的要求--获取所有的sensor readout。
// retrieveSnapshotsSequentiallyImproved
IObjectSet result = db.Get(typeof(Car));
Car car = (Car)result.Next();
SensorReadout readout = car.GetHistory();
while (readout != null)


{
db.Activate(readout, 1);
Console.WriteLine(readout);
readout = readout.Next;
}
注意:“消减”引用也会影响对象的行动。在这个例子中,列表的长度是动态计算的,是被激活深度限制的。
不用动态激活深度的话,你可以静态的设置激活深度。可以告诉sensor readout类的对象来自动的瀑布式(递归)的激活。如下面的例子:
// setActivationDepth
Db4oFactory.Configure().ObjectClass(typeof(TemperatureSensorReadout))
.CascadeOnActivate(true);
// retrieveSnapshotsSequentially
IObjectSet result = db.Get(typeof(Car));
Car car = (Car)result.Next();
SensorReadout readout = car.GetHistory();
while (readout != null)


{
Console.WriteLine(readout);
readout = readout.Next;
}
因为激活深度很复杂,所以你要非常小心。db4o提供了一个很宽范围的设置属性来控制激活深度。这些操作在
Db4objects.Db4o.Config.Configuration 类中,并且与IObjectClass and IObjectField有一定关系。
不要忘记清空数据库。
// deleteAll
IObjectSet result = db.Get(typeof(Object));
foreach (object item in result)


{
db.Delete(item);
}
7.3. 总结
现在,我们已经可以处理复杂的类了。但是,这些都在这样的一个假设下:所有的操作都是对的,当你需要会滚操作的时候该怎么办呢?在下一章节将讲到这个问题。
7.4. 全部代码:
锘縰sing System;
using System.IO;
using Db4objects.Db4o;
namespace Db4objects.Db4o.Tutorial.F1.Chapter5


{
public class DeepExample : Util

{
public static void Main(string[] args)

{
File.Delete(Util.YapFileName);
IObjectContainer db = Db4oFactory.OpenFile(Util.YapFileName);
try

{
StoreCar(db);
db.Close();
SetCascadeOnUpdate();
db = Db4oFactory.OpenFile(Util.YapFileName);
TakeManySnapshots(db);
db.Close();
db = Db4oFactory.OpenFile(Util.YapFileName);
RetrieveAllSnapshots(db);
db.Close();
db = Db4oFactory.OpenFile(Util.YapFileName);
RetrieveSnapshotsSequentially(db);
RetrieveSnapshotsSequentiallyImproved(db);
db.Close();
SetActivationDepth();
db = Db4oFactory.OpenFile(Util.YapFileName);
RetrieveSnapshotsSequentially(db);
}
finally

{
db.Close();
}
}
public static void StoreCar(IObjectContainer db)

{
Pilot pilot = new Pilot("Rubens Barrichello", 99);
Car car = new Car("BMW");
car.Pilot = pilot;
db.Set(car);
}
public static void SetCascadeOnUpdate()

{
Db4oFactory.Configure().ObjectClass(typeof(Car)).CascadeOnUpdate(true);
}
public static void TakeManySnapshots(IObjectContainer db)

{
IObjectSet result = db.Get(typeof(Car));
Car car = (Car)result.Next();
for (int i=0; i<5; i++)

{
car.Snapshot();
}
db.Set(car);
}
public static void RetrieveAllSnapshots(IObjectContainer db)

{
IObjectSet result = db.Get(typeof(SensorReadout));
while (result.HasNext())

{
Console.WriteLine(result.Next());
}
}
public static void RetrieveSnapshotsSequentially(IObjectContainer db)

{
IObjectSet result = db.Get(typeof(Car));
Car car = (Car)result.Next();
SensorReadout readout = car.GetHistory();
while (readout != null)

{
Console.WriteLine(readout);
readout = readout.Next;
}
}
public static void RetrieveSnapshotsSequentiallyImproved(IObjectContainer db)

{
IObjectSet result = db.Get(typeof(Car));
Car car = (Car)result.Next();
SensorReadout readout = car.GetHistory();
while (readout != null)

{
db.Activate(readout, 1);
Console.WriteLine(readout);
readout = readout.Next;
}
}
public static void SetActivationDepth()

{
Db4oFactory.Configure().ObjectClass(typeof(TemperatureSensorReadout))
.CascadeOnActivate(true);
}
}
}
