<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <link rel="stylesheet" type="text/css" href="docs.css"> <!--[if gte IE 5]> <link href="docs_ie.css" rel="stylesheet" type="text/css"> <![endif]--> </head> <body><div id="pagecontainer"><table><tr><td width="5"> </td><td><a name="TransparentActivation"></a><br> <a name="outline200"></a><br><h1>10. Transparent Activation</h1><br> Let's take a second look at the concept of Activation. We have seen how db4o uses a "depth" concept by default to activate objects to a specific depth when they are returned from a query.<br> <br> Wouldn't it be a lot nicer, if an application would never have to worry about activating objects and if db4o could handle things transparently for us? This is what Transparent Activation was developed for.<br> <br> <ul> <a name="outline201"></a><br><h2>10.1. The Activation Problem</h2><br> We can reuse most of the code from the <a href="Deep.html#Deep">Deep Graphs chapter</a> and get it to work with Transparent Activation.<br> <br> As a first step we should fill up our database with Car, Pilot and SensorReadout objects, so we have some objects to work with.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// storeCarAndSnapshots<br> Pilot pilot = new Pilot("Kimi Raikkonen", 110);<br> Car car = new Car("Ferrari");<br> car.Pilot = pilot;<br> for (int i = 0; i < 5; i++)<br> {<br> car.snapshot();<br> }<br> db.Store(car);</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter8.TransparentActivationExample", "storeCarAndSnapshots")' /></td></tr></table> <br> <br> If we now rerun the code to traverse all cars and their sensor readings, we are again confronted with the same problem that we had before, we end up with some leaves of our object graph being null. <br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveSnapshotsSequentially<br> IObjectSet result = db.QueryByExample(typeof (Car));<br> Car car = (Car) result.Next();<br> SensorReadout readout = car.History;<br> while (readout != null)<br> {<br> Console.WriteLine(readout);<br> readout = readout.Next;<br> }</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter8.TransparentActivationExample", "retrieveSnapshotsSequentially")' /></td></tr></table> <br> <br> <a name="outline202"></a><br><h2>10.2. Turning On Transparent Activation</h2><br> Let's configure db4o to run in Transparent Activation mode and let's try again:<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveSnapshotsSequentiallyTA<br> IEmbeddedConfiguration config = Db4oEmbedded.NewConfiguration();<br> config.Common.Add(new TransparentActivationSupport());<br> using(IObjectContainer db = Db4oEmbedded.OpenFile(config, YapFileName))<br> {<br> IObjectSet result = db.QueryByExample(typeof(Car));<br> Car car = (Car)result.Next();<br> SensorReadout readout = car.History;<br> while (readout != null)<br> {<br> Console.WriteLine(readout);<br> readout = readout.Next;<br> }<br> }</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter8.TransparentActivationExample", "retrieveSnapshotsSequentiallyTA")' /></td></tr></table> <br> <br> Wow it worked! Is it really that easy? Principally yes. When db4o is run in Transparent Activation mode there are no surprises with null members that have not yet been read from the database. <br> <br> <a name="outline203"></a><br><h2>10.3. Implementing IActivatable</h2> <br> <br> When Transparent Activation is turned on, all objects that do not implement the Db4objects.Db4o.TA.IActivatable interface will be fully activated when they are used. <br> <br> Although we wont get any surprises with null objects when we work in this mode, access to the root of a deep graph may load the entire graph into memory and that can take a long time and use a lot of memory.<br> <br> To prevent immediate activation of a class you can implement the IActivatable interface. Whenever db4o comes across an Activatable object while activating a graph of objects it will stop traversing the graph any deeper. db4o will "know" that it can activate Activatable objects on demand, so there is no reason to continue activation until these objects are really needed. <br> <br> For demonstration purposes we have made all classes used in this example Activatable and we have also added all the code required to activate by hand.<br> <br> Let's take a look at the Activatable version of our Car class:<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>using System;<br> using Db4objects.Db4o;<br> using Db4objects.Db4o.Activation;<br> using Db4objects.Db4o.TA;<br> namespace Db4odoc.Tutorial.F1.Chapter8<br> {<br> public class Car : IActivatable <br> {<br> private readonly String _model;<br> private Pilot _pilot;<br> private SensorReadout _history;<br> <br> [Transient]<br> private IActivator _activator;<br> public Car(String model) <br> {<br> this._model=model;<br> this._pilot=null;<br> this._history=null;<br> }<br> public Pilot Pilot<br> {<br> get<br> {<br> Activate(ActivationPurpose.Read);<br> return _pilot;<br> }<br> set<br> {<br> Activate(ActivationPurpose.Write);<br> this._pilot = value;<br> }<br> }<br> <br> public Pilot PilotWithoutActivation<br> {<br> get { return _pilot; }<br> }<br> public String Model<br> {<br> get<br> {<br> Activate(ActivationPurpose.Read);<br> return _model;<br> }<br> }<br> <br> public SensorReadout History<br> {<br> get<br> {<br> Activate(ActivationPurpose.Read);<br> return _history;<br> }<br> }<br> <br> public void snapshot() <br> { <br> AppendToHistory(new TemperatureSensorReadout(DateTime.Now,this,"oil", PollOilTemperature()));<br> AppendToHistory(new TemperatureSensorReadout(DateTime.Now, this, "water", PollWaterTemperature()));<br> AppendToHistory(new PressureSensorReadout(DateTime.Now, this, "oil", PollOilPressure()));<br> }<br> protected double PollOilTemperature() <br> {<br> return 0.1* CountHistoryElements();<br> }<br> protected double PollWaterTemperature() <br> {<br> return 0.2* CountHistoryElements();<br> }<br> protected double PollOilPressure() <br> {<br> return 0.3* CountHistoryElements();<br> }<br> public override String ToString() <br> {<br> Activate(ActivationPurpose.Read);<br> return string.Format("{0}[{1}]/{2}", _model, _pilot, CountHistoryElements());<br> }<br> <br> private int CountHistoryElements() <br> {<br> Activate(ActivationPurpose.Read);<br> return (_history==null ? 0 : _history.CountElements());<br> }<br> <br> private void AppendToHistory(SensorReadout readout) <br> {<br> Activate(ActivationPurpose.Write);<br> if(_history==null) <br> {<br> _history=readout;<br> }<br> else <br> {<br> _history.Append(readout);<br> }<br> }<br> public void Activate(ActivationPurpose purpose) <br> {<br> if(_activator != null) <br> {<br> _activator.Activate(purpose);<br> }<br> }<br> public void Bind(IActivator activator) <br> {<br> if (_activator == activator)<br> {<br> return;<br> }<br> if (activator != null && null != _activator)<br> {<br> throw new System.InvalidOperationException();<br> }<br> _activator = activator;<br> }<br> }<br> }<br> </code></td></tr></table> <br> <br> Can you spot the member _activator, all the # Activate() calls and the two methods # Activate() and # Bind( IActivator) at the end?<br> <br> An Activatable class should store the Activator that db4o provides to the bind method in a transient variable and call # Activate() on this Activator before any field is accessed.<br> <br> If the object is already activated, the method will return immediately. If it is not, activation will happen at this time.<br> <br> We have added the PilotWithoutActivation property to the Car class to be able to demonstrate.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// demonstrateTransparentActivation<br> IEmbeddedConfiguration config = Db4oEmbedded.NewConfiguration();<br> config.Common.Add(new TransparentActivationSupport());<br> using(IObjectContainer db = Db4oEmbedded.OpenFile(config, YapFileName)){<br> IObjectSet result = db.QueryByExample(typeof (Car));<br> Car car = (Car) result.Next();<br> Console.WriteLine("#PilotWithoutActivation before the car is activated");<br> Console.WriteLine(car.PilotWithoutActivation);<br> Console.WriteLine("accessing 'Pilot' property activates the car object");<br> Console.WriteLine(car.Pilot);<br> Console.WriteLine("Accessing PilotWithoutActivation property after the car is activated");<br> Console.WriteLine(car.PilotWithoutActivation);<br> }</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter8.TransparentActivationExample", "demonstrateTransparentActivation")' /></td></tr></table> <br> <br> <a name="outline204"></a><br><h2>10.4. Where Enhancement can help</h2><br> If all this Activatable code in a persistent class looked like a lot of typing work, do not worry: db4o comes with a tool to add this code automatically to all of your persistent classes. Read more about it in the chapter on <a href="Enhancement.html#Enhancement">Enhancement</a> . <br> <br> As a final step we should clean up the database again.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// deleteAll<br> IObjectSet result = db.QueryByExample(typeof(Object));<br> foreach (object item in result)<br> {<br> db.Delete(item);<br> }</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.Util", "deleteAll")' /></td></tr></table> <br> <br> <a name="outline205"></a><br><h2>10.5. Conclusion</h2><br> This was just a short introduction to Transparent Activation and what it can do for you. For more detailed information please see the pages on Transparent Activation in our <a href="http://developer.db4o.com/Documentation.aspx" target="_blank">online reference</a> or in your offline copy of the Reference documentation.<br> <br> <a name="outline206"></a><br><h2>10.6. Full source</h2><br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>using System;<br> using System.IO;<br> using Db4objects.Db4o;<br> using Db4objects.Db4o.Config;<br> using Db4objects.Db4o.TA;<br> using Db4odoc.Tutorial.F1;<br> namespace Db4odoc.Tutorial.F1.Chapter8<br> {<br> public class TransparentActivationExample : Util<br> {<br> readonly static string YapFileName = Path.Combine(<br> Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),<br> "formula1.yap"); <br> <br> public static void Main(String[] args)<br> {<br> File.Delete(YapFileName);<br> using(IObjectContainer db = Db4oEmbedded.OpenFile(YapFileName))<br> {<br> StoreCarAndSnapshots(db);<br> }<br> using(IObjectContainer db = Db4oEmbedded.OpenFile(YapFileName))<br> {<br> RetrieveSnapshotsSequentially(db);<br> }<br> RetrieveSnapshotsSequentiallyTA();<br> DemonstrateTransparentActivation();<br> }<br> <br> public static void StoreCarAndSnapshots(IObjectContainer db)<br> {<br> Pilot pilot = new Pilot("Kimi Raikkonen", 110);<br> Car car = new Car("Ferrari");<br> car.Pilot = pilot;<br> for (int i = 0; i < 5; i++)<br> {<br> car.snapshot();<br> }<br> db.Store(car);<br> }<br> public static void RetrieveSnapshotsSequentially(IObjectContainer db)<br> {<br> IObjectSet result = db.QueryByExample(typeof (Car));<br> Car car = (Car) result.Next();<br> SensorReadout readout = car.History;<br> while (readout != null)<br> {<br> Console.WriteLine(readout);<br> readout = readout.Next;<br> }<br> }<br> public static void RetrieveSnapshotsSequentiallyTA()<br> {<br> IEmbeddedConfiguration config = Db4oEmbedded.NewConfiguration();<br> config.Common.Add(new TransparentActivationSupport());<br> using(IObjectContainer db = Db4oEmbedded.OpenFile(config, YapFileName))<br> {<br> IObjectSet result = db.QueryByExample(typeof(Car));<br> Car car = (Car)result.Next();<br> SensorReadout readout = car.History;<br> while (readout != null)<br> {<br> Console.WriteLine(readout);<br> readout = readout.Next;<br> }<br> }<br> }<br> public static void DemonstrateTransparentActivation()<br> {<br> IEmbeddedConfiguration config = Db4oEmbedded.NewConfiguration();<br> config.Common.Add(new TransparentActivationSupport());<br> <br> using(IObjectContainer db = Db4oEmbedded.OpenFile(config, YapFileName)){<br> IObjectSet result = db.QueryByExample(typeof (Car));<br> Car car = (Car) result.Next();<br> Console.WriteLine("#PilotWithoutActivation before the car is activated");<br> Console.WriteLine(car.PilotWithoutActivation);<br> Console.WriteLine("accessing 'Pilot' property activates the car object");<br> Console.WriteLine(car.Pilot);<br> Console.WriteLine("Accessing PilotWithoutActivation property after the car is activated");<br> Console.WriteLine(car.PilotWithoutActivation);<br> }<br> }<br> }<br> }<br> </code></td></tr></table> <br> <br><br><div id="footer"><p align="center">Do you have any questions, suggestions or feedback? Ask your questions in the <a href="http://developer.db4o.com/Forums.aspx" target=_top>db4o forums</a>. Join the <a href="http://developer.db4o.com" target=_top>db4o community</a> for addional resources and news.<br><br><a href="http://www.db4o.com/" target=_top><small>www.db4o.com</small></a></p>.</div><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br></td></tr></table></div></body></html>