Detailed Example

Let's look at a primitive example, demonstrating manual implementation of Activatable/IActivatable interface for TP. We will use a class similar to the one used in Transparent Activation chapters.

SensorPanel.cs
001/* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com */ 002using Db4objects.Db4o; 003using Db4objects.Db4o.Activation; 004using Db4objects.Db4o.TA; 005 006namespace Db4ojects.Db4odoc.TPExample 007{ 008 public class SensorPanel /*must implement Activatable for TA and TP */: IActivatable 009 { 010 private object _sensor; 011 012 private SensorPanel _next; 013 014 /*activator registered for this class*/ 015 [System.NonSerialized] 016 IActivator _activator; 017 018 public SensorPanel() 019 { 020 // default constructor for instantiation 021 } 022 // end SensorPanel 023 024 public SensorPanel(int value) 025 { 026 _sensor = value; 027 } 028 // end SensorPanel 029 030 /*Bind the class to the specified object container, create the activator*/ 031 public void Bind(IActivator activator) 032 { 033 if (_activator == activator) 034 { 035 return; 036 } 037 if (activator != null && null != _activator) 038 { 039 throw new System.InvalidOperationException(); 040 } 041 _activator = activator; 042 } 043 // end Bind 044 045 /*Call the registered activator to activate the next level, 046 * the activator remembers the objects that were already 047 * activated and won't activate them twice. 048 */ 049 public void Activate(ActivationPurpose purpose) 050 { 051 if (_activator == null) 052 return; 053 _activator.Activate(purpose); 054 } 055 // end Activate 056 057 public SensorPanel Next 058 { 059 get 060 { 061 /*activate direct members*/ 062 Activate(ActivationPurpose.Read); 063 return _next; 064 } 065 } 066 // end Next 067 068 public object Sensor 069 { 070 get 071 { 072 /*activate direct members*/ 073 Activate(ActivationPurpose.Read); 074 return _sensor; 075 } 076 set 077 { 078 /*activate for persistense*/ 079 Activate(ActivationPurpose.Write); 080 _sensor = value; 081 } 082 } 083 // end Sensor 084 085 public SensorPanel CreateList(int length) 086 { 087 return CreateList(length, 1); 088 } 089 // end CreateList 090 091 public SensorPanel CreateList(int length, int first) 092 { 093 int val = first; 094 SensorPanel root = NewElement(first); 095 SensorPanel list = root; 096 while (--length > 0) 097 { 098 list._next = NewElement(++val); 099 list = list.Next; 100 } 101 return root; 102 } 103 // end CreateList 104 105 protected SensorPanel NewElement(int value) 106 { 107 return new SensorPanel(value); 108 } 109 // end NewElement 110 111 public override string ToString() 112 { 113 return "Sensor #" + Sensor; 114 } 115 // end ToString 116 } 117 118}
SensorPanel.vb
001' Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com 002Imports Db4objects.Db4o 003Imports Db4objects.Db4o.Activation 004Imports Db4objects.Db4o.TA 005 006Namespace Db4ojects.Db4odoc.TPExample 007 008 Public Class SensorPanel ' must implement Activatable for TA and TP 009 Implements IActivatable 010 011 Private _sensor As Object 012 Private _next As SensorPanel 013 014 ' activator registered for this class 015 <Transient()> _ 016 Private _activator As IActivator 017 018 Public Sub New() 019 End Sub 020 ' end New 021 022 Public Sub New(ByVal value As Integer) 023 _sensor = value 024 End Sub 025 ' end New 026 027 ' Bind the class to the specified object container, create the activator 028 Public Sub Bind(ByVal activator As IActivator) Implements IActivatable.Bind 029 If _activator Is activator Then 030 Return 031 End If 032 If Not (activator Is Nothing Or _activator Is Nothing) Then 033 Throw New System.InvalidOperationException() 034 End If 035 _activator = activator 036 End Sub 037 ' end Bind 038 039 'Call the registered activator to activate the next level, 040 ' the activator remembers the objects that were already 041 ' activated and won't activate them twice. 042 Public Sub Activate(ByVal purpose As ActivationPurpose) Implements IActivatable.Activate 043 If _activator Is Nothing Then 044 Return 045 End If 046 _activator.Activate(ActivationPurpose.Read) 047 End Sub 048 ' end Activate 049 050 Public ReadOnly Property NextSensor() As SensorPanel 051 Get 052 ' activate direct members 053 Activate(ActivationPurpose.Read) 054 Return _next 055 End Get 056 End Property 057 ' end NextSensor 058 059 Public Property Sensor() As Object 060 Get 061 ' activate direct members 062 Activate(ActivationPurpose.Read) 063 Return _sensor 064 End Get 065 Set(ByVal value As Object) 066 ' activate for persistence 067 Activate(ActivationPurpose.Write) 068 _sensor = value 069 End Set 070 End Property 071 ' end Sensor 072 073 Public Function CreateList(ByVal length As Integer) As SensorPanel 074 Return CreateList(length, 1) 075 End Function 076 ' end CreateList 077 078 Public Function CreateList(ByVal length As Integer, ByVal first As Integer) As SensorPanel 079 Dim val As Integer = first 080 Dim root As SensorPanel = NewElement(first) 081 Dim list As SensorPanel = root 082 While System.Threading.Interlocked.Decrement(length) > 0 083 list._next = NewElement(System.Threading.Interlocked.Increment(val)) 084 list = list.NextSensor 085 End While 086 Return root 087 End Function 088 ' end CreateList 089 090 Protected Function NewElement(ByVal value As Integer) As SensorPanel 091 Return New SensorPanel(value) 092 End Function 093 ' end NewElement 094 095 Public Overloads Overrides Function ToString() As String 096 Return "Sensor #" + Sensor.ToString() 097 End Function 098 ' end ToString 099 End Class 100End Namespace

Note, that the only place where we can modify SensorPanel members is setSensor method/Sensor property, and that is where activate method is added.

Now we will only need to add Transparent Activation support:

TPExample.cs: ConfigureTA
1private static IConfiguration ConfigureTA() 2 { 3 IConfiguration configuration = Db4oFactory.NewConfiguration(); 4 // add TA support 5 configuration.Add(new TransparentActivationSupport()); 6 return configuration; 7 }
TPExample.vb: ConfigureTA
1Private Shared Function ConfigureTA() As IConfiguration 2 Dim configuration As IConfiguration = Db4oFactory.NewConfiguration 3 ' add TA support 4 configuration.Add(New TransparentActivationSupport) 5 Return configuration 6 End Function

Initial storing of the objects is done as usual with a single store call:

TPExample.cs: StoreSensorPanel
01private static void StoreSensorPanel() 02 { 03 File.Delete(Db4oFileName); 04 IObjectContainer container = Database(Db4oFactory.NewConfiguration()); 05 if (container != null) 06 { 07 try 08 { 09 // create a linked list with length 10 10 SensorPanel list = new SensorPanel().CreateList(10); 11 container.Store(list); 12 } 13 finally 14 { 15 CloseDatabase(); 16 } 17 } 18 }
TPExample.vb: StoreSensorPanel
01Private Shared Sub StoreSensorPanel() 02 File.Delete(Db4oFileName) 03 Dim container As IObjectContainer = Database(Db4oFactory.NewConfiguration) 04 If Not (container Is Nothing) Then 05 Try 06 ' create a linked list with length 10 07 Dim list As SensorPanel = (New SensorPanel).CreateList(10) 08 container.Set(list) 09 Finally 10 CloseDatabase() 11 End Try 12 End If 13 End Sub

Now we can test how Transparent Persistence helped us to keep the code simple. Let's select all elements from the linked SensorPanel list, modify them and store. As you remember default update depth is one, so without TP, we would have to store each member of the linked list (SensorPanel) separately. With TP enabled there is absolutely nothing to do: commit call will find all activatable objects and store those that were modified.

TPExample.cs: TestTransparentPersistence
01private static void TestTransparentPersistence() 02 { 03 StoreSensorPanel(); 04 IConfiguration configuration = ConfigureTA(); 05 06 IObjectContainer container = Database(configuration); 07 if (container != null) 08 { 09 try 10 { 11 IObjectSet result = container.QueryByExample(new SensorPanel(1)); 12 ListResult(result); 13 SensorPanel sensor = null; 14 if (result.Size() > 0) 15 { 16 System.Console.WriteLine("Before modification: "); 17 sensor = (SensorPanel)result[0]; 18 // the object is a linked list, so each call to next() 19 // will need to activate a new object 20 SensorPanel next = sensor.Next; 21 while (next != null) 22 { 23 System.Console.WriteLine(next); 24 // modify the next sensor 25 next.Sensor = (object)(10 + (int)next.Sensor); 26 next = next.Next; 27 } 28 // Explicit commit stores and commits the changes at any time 29 container.Commit(); 30 } 31 } 32 finally 33 { 34 // If there are unsaved changes to activatable objects, they 35 // will be implicitly saved and committed when the database 36 // is closed 37 CloseDatabase(); 38 } 39 } 40 // reopen the database and check the modifications 41 container = Database(configuration); 42 if (container != null) 43 { 44 try 45 { 46 IObjectSet result = container.QueryByExample(new SensorPanel(1)); 47 ListResult(result); 48 SensorPanel sensor = null; 49 if (result.Size() > 0) 50 { 51 System.Console.WriteLine("After modification: "); 52 sensor = (SensorPanel)result[0]; 53 SensorPanel next = sensor.Next; 54 while (next != null) 55 { 56 System.Console.WriteLine(next); 57 next = next.Next; 58 } 59 } 60 } 61 finally 62 { 63 CloseDatabase(); 64 } 65 } 66 }
TPExample.vb: TestTransparentPersistence
01Private Shared Sub TestTransparentPersistence() 02 StoreSensorPanel() 03 Dim configuration As IConfiguration = ConfigureTA() 04 Dim container As IObjectContainer = Database(configuration) 05 If Not (container Is Nothing) Then 06 Try 07 Dim result As IObjectSet = container.QueryByExample(New SensorPanel(1)) 08 Dim sensor As SensorPanel = Nothing 09 ListResult(result) 10 If result.Size > 0 Then 11 System.Console.WriteLine("Before modification: ") 12 sensor = CType(result(0), SensorPanel) 13 ' the object is a linked list, so each call to next() 14 ' will need to activate a new object 15 Dim nextSensor As SensorPanel = sensor.NextSensor 16 While Not (nextSensor Is Nothing) 17 System.Console.WriteLine(nextSensor) 18 ' modify the next sensor 19 nextSensor.Sensor = CType((10 + CType(nextSensor.Sensor, Int32)), Object) 20 nextSensor = nextSensor.NextSensor 21 End While 22 End If 23 Finally 24 CloseDatabase() 25 End Try 26 End If 27 ' reopen the database and check the modifications 28 container = Database(configuration) 29 If Not (container Is Nothing) Then 30 Try 31 Dim result As IObjectSet = container.QueryByExample(New SensorPanel(1)) 32 Dim sensor As SensorPanel = Nothing 33 ListResult(result) 34 If result.Size > 0 Then 35 System.Console.WriteLine("After modification: ") 36 sensor = CType(result(0), SensorPanel) 37 Dim nextSensor As SensorPanel = sensor.NextSensor 38 While Not (nextSensor Is Nothing) 39 System.Console.WriteLine(nextSensor) 40 nextSensor = nextSensor.NextSensor 41 End While 42 End If 43 Finally 44 CloseDatabase() 45 End Try 46 End If 47 End Sub

That's all. The benefits that we've got: