7. Deep graphs


We have already seen how db4o handles object associations, but our running example is still quite flat and simple, compared to real-world domain models. In particular we haven't seen how db4o behaves in the presence of recursive structures. We will emulate such a structure by replacing our history list with a linked list implicitely provided by the SensorReadout class.

Imports System
Namespace com.db4o.f1.chapter5
    Public Class SensorReadout
        Private _time As DateTime
        Private _car As Car
        Private _description As String
        Private _next As SensorReadout
        Protected Sub New(ByVal time As DateTime, ByVal car As Car, ByVal description As String)
            _time = time
            _car = car
            _description = description
            _next = Nothing
        End Sub
        Public ReadOnly Property Car() As Car
            Get
                Return _car
            End Get
        End Property
        Public ReadOnly Property Time() As DateTime
            Get
                Return _time
            End Get
        End Property
        Public ReadOnly Property [Next]() As SensorReadout
            Get
                Return _next
            End Get
        End Property
        Public Sub Append(ByVal sensorReadout As SensorReadout)
            If _next Is Nothing Then
                _next = sensorReadout
            Else
                _next.Append(sensorReadout)
            End If
        End Sub
        Public Function CountElements() As Integer
            If _next Is Nothing Then
                Return 1
            End If
            Return _next.CountElements() + 1
        End Function
        Public Overloads Overrides Function ToString() As String
            Return String.Format("{0} : {1} : {2}", _car, _time, _description)
        End Function
    End Class
End Namespace


Our car only maintains an association to a 'head' sensor readout now.

Imports System
Namespace com.db4o.f1.chapter5
    Public Class Car
        Private _model As String
        Private _pilot As Pilot
        Private _history As SensorReadout
        Public Sub New(ByVal model As String)
            _model = model
            _pilot = Nothing
            _history = Nothing
        End Sub
        Public Property Pilot() As Pilot
            Get
                Return _pilot
            End Get
            Set
                _pilot = value
            End Set
        End Property
        Public ReadOnly Property Model() As String
            Get
                Return _model
            End Get
        End Property
        Public Function GetHistory() As SensorReadout
            Return _history
        End Function
        Public Sub Snapshot()
            AppendToHistory(New TemperatureSensorReadout(DateTime.Now, Me, "oil", PollOilTemperature()))
            AppendToHistory(New TemperatureSensorReadout(DateTime.Now, Me, "water", PollWaterTemperature()))
            AppendToHistory(New PressureSensorReadout(DateTime.Now, Me, "oil", PollOilPressure()))
        End Sub
        Protected Function PollOilTemperature() As Double
            Return 0.1 * CountHistoryElements()
        End Function
        Protected Function PollWaterTemperature() As Double
            Return 0.2 * CountHistoryElements()
        End Function
        Protected Function PollOilPressure() As Double
            Return 0.3 * CountHistoryElements()
        End Function
        Public Overloads Overrides Function ToString() As String
            Return String.Format("{0}[{1}]/{2}", _model, _pilot, CountHistoryElements())
        End Function
        Private Function CountHistoryElements() As Integer
            If _history Is Nothing Then
                Return 0
            End If
            Return _history.CountElements()
        End Function
        Private Sub AppendToHistory(ByVal readout As SensorReadout)
            If _history Is Nothing Then
                _history = readout
            Else
                _history.Append(readout)
            End If
        End Sub
    End Class
End Namespace



    7.1. Storing and updating


    No surprises here.

    [storeCar]
    Dim pilot As Pilot = New Pilot("Rubens Barrichello", 99)
    Dim car As Car = New Car("BMW")
    car.Pilot = pilot
    db.[Set](car)


    Now we would like to build a sensor readout chain. We already know about the update depth trap, so we configure this first.

    [setCascadeOnUpdate]
    Db4oFactory.Configure().ObjectClass(GetType(Car)).CascadeOnUpdate(True)


    Let's collect a few sensor readouts.

    [takeManySnapshots]
    Dim result As ObjectSet = db.[Get](GetType(Car))
    Dim car As Car = DirectCast(result.[Next](), Car)
    Dim i As Integer = 0
    While i < 5
        car.Snapshot()
        System.Math.Max(System.Threading.Interlocked.Increment(i),i - 1)
    End While
    db.[Set](car)



    7.2. Retrieving


    Now that we have a sufficiently deep structure, we'll retrieve it from the database and traverse it.

    First let's verify that we indeed have taken lots of snapshots.

    [retrieveAllSnapshots]
    Dim result As ObjectSet = db.[Get](GetType(SensorReadout))
    While result.HasNext()
        Console.WriteLine(result.[Next]())
    End While
    OUTPUT:
    BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil pressure : 4.2
    BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : water temp : 2.6
    BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil temp : 1.2000000000000002
    BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil pressure : 3.3
    BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : water temp : 2.0
    BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil temp : 0.9
    BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil pressure : 2.4
    BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil temp : 0.6000000000000001
    BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil pressure : 0.6
    BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : water temp : 1.4000000000000001
    BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil pressure : 1.5
    BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : water temp : 0.8
    BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil temp : 0.30000000000000004
    BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : water temp : 0.2
    BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil temp : 0.0


All these readouts belong to one linked list, so we should be able to access them all by just traversing our list structure.

[retrieveSnapshotsSequentially]
Dim result As ObjectSet = db.[Get](GetType(Car))
Dim car As Car = DirectCast(result.[Next](), Car)
Dim readout As SensorReadout = car.GetHistory()
While Not readout Is Nothing
    Console.WriteLine(readout)
    readout = readout.[Next]
End While
OUTPUT:
BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil temp : 0.0
BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : water temp : 0.2
BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil pressure : 0.6
BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil temp : 0.30000000000000004
BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : water temp : 0.8
BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil pressure : 1.5
BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil temp : 0.6000000000000001
BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : water temp : 1.4000000000000001
BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil pressure : 2.4
BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil temp : 0.9
BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : water temp : 2.0
BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil pressure : 3.3
BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil temp : 1.2000000000000002
BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : water temp : 2.6
BMW[Rubens Barrichello/99]/15 : Wed Jul 05 10:33:49 CEST 2006 : oil pressure : 4.2


Ouch! What's happening here?



7.3. Conclusion


Now we should have the tools at hand to work with arbitrarily complex object graphs. But so far we have only been working forward, hoping that the changes we apply to our precious data pool are correct. What if we have to roll back to a previous state due to some failure? In the next chapter  we will introduce the db4o transaction concept.


7.4. Full source


Imports System
Imports System.IO
Imports com.db4o
Namespace com.db4o.f1.chapter5
    Public Class DeepExample
    Inherits Util
        Public Shared Sub Main(ByVal args As String())
            File.Delete(Util.YapFileName)
            Dim db As ObjectContainer = 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()
            End Try
        End Sub
        Public Shared Sub StoreCar(ByVal db As ObjectContainer)
            Dim pilot As Pilot = New Pilot("Rubens Barrichello", 99)
            Dim car As Car = New Car("BMW")
            car.Pilot = pilot
            db.[Set](car)
        End Sub
        Public Shared Sub SetCascadeOnUpdate()
            Db4oFactory.Configure().ObjectClass(GetType(Car)).CascadeOnUpdate(True)
        End Sub
        Public Shared Sub TakeManySnapshots(ByVal db As ObjectContainer)
            Dim result As ObjectSet = db.[Get](GetType(Car))
            Dim car As Car = DirectCast(result.[Next](), Car)
            Dim i As Integer = 0
            While i < 5
                car.Snapshot()
                System.Math.Max(System.Threading.Interlocked.Increment(i),i - 1)
            End While
            db.[Set](car)
        End Sub
        Public Shared Sub RetrieveAllSnapshots(ByVal db As ObjectContainer)
            Dim result As ObjectSet = db.[Get](GetType(SensorReadout))
            While result.HasNext()
                Console.WriteLine(result.[Next]())
            End While
        End Sub
        Public Shared Sub RetrieveSnapshotsSequentially(ByVal db As ObjectContainer)
            Dim result As ObjectSet = db.[Get](GetType(Car))
            Dim car As Car = DirectCast(result.[Next](), Car)
            Dim readout As SensorReadout = car.GetHistory()
            While Not readout Is Nothing
                Console.WriteLine(readout)
                readout = readout.[Next]
            End While
        End Sub
        Public Shared Sub RetrieveSnapshotsSequentiallyImproved(ByVal db As ObjectContainer)
            Dim result As ObjectSet = db.[Get](GetType(Car))
            Dim car As Car = DirectCast(result.[Next](), Car)
            Dim readout As SensorReadout = car.GetHistory()
            While Not readout Is Nothing
                db.Activate(readout, 1)
                Console.WriteLine(readout)
                readout = readout.[Next]
            End While
        End Sub
        Public Shared Sub SetActivationDepth()
            Db4oFactory.Configure().ObjectClass(GetType(TemperatureSensorReadout)).CascadeOnActivate(True)
        End Sub
    End Class
End Namespace




--
generated by
Doctor courtesy of db4objects Inc.