5. Collections and Arrays


We will slowly move towards real-time data processing now by installing sensors to our car and collecting their output.

Imports System
Imports System.Text
Namespace com.db4o.f1.chapter3
    Public Class SensorReadout
        Private _values As Double()
        Private _time As DateTime
        Private _car As Car
        Public Sub New(ByVal values As Double(), ByVal time As DateTime, ByVal car As Car)
            _values = values
            _time = time
            _car = car
        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 NumValues() As Integer
            Get
                Return _values.Length
            End Get
        End Property
        Public ReadOnly Property Values() As Double()
            Get
                Return _values
            End Get
        End Property
        Public Function GetValue(ByVal idx As Integer) As Double
            Return _values(idx)
        End Function
        Public Overloads Overrides Function ToString() As String
            Dim builder As StringBuilder = New StringBuilder()
            builder.Append(_car)
            builder.Append(" : ")
            builder.Append(_time.TimeOfDay)
            builder.Append(" : ")
            Dim i As Integer = 0
            While i < _values.Length
                If i > 0 Then
                    builder.Append(", ")
                End If
                builder.Append(_values(i))
                System.Threading.Interlocked.Increment(i)
            End While
            Return builder.ToString()
        End Function
    End Class
End Namespace


A car may produce its current sensor readout when requested and keep a list of readouts collected during a race.

Imports System
Imports System.Collections
Namespace com.db4o.f1.chapter3
    Public Class Car
        Private _model As String
        Private _pilot As Pilot
        Private _history As IList
        Public Sub New(ByVal model As String)
            Me.New(model, New ArrayList())
        End Sub
        Public Sub New(ByVal model As String, ByVal history As IList)
            _model = model
            _pilot = Nothing
            _history = history
        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 ReadOnly Property History() As IList
            Get
                Return _history
            End Get
        End Property
        Public Sub Snapshot()
            _history.Add(New SensorReadout(Poll(), DateTime.Now, Me))
        End Sub
        Protected Function Poll() As Double()
            Dim factor As Integer = _history.Count + 1
            Return New Double() {0.1 * factor, 0.2 * factor, 0.3 * factor}
        End Function
        Public Overloads Overrides Function ToString() As String
            Return String.Format("{0}[{1}]/{2}", _model, _pilot, _history.Count)
        End Function
    End Class
End Namespace


We will constrain ourselves to rather static data at the moment and add flexibility during the next chapters.


    5.1. Storing


    This should be familiar by now.

    [storeFirstCar]
    Dim car1 As Car = New Car("Ferrari")
    Dim pilot1 As Pilot = New Pilot("Michael Schumacher", 100)
    car1.Pilot = pilot1
    db.[Set](car1)


    The second car will take two snapshots immediately at startup.

    [storeSecondCar]
    Dim pilot2 As Pilot = New Pilot("Rubens Barrichello", 99)
    Dim car2 As Car = New Car("BMW")
    car2.Pilot = pilot2
    car2.Snapshot()
    car2.Snapshot()
    db.[Set](car2)



    5.2. Retrieving



      5.2.1. QBE


      First let us verify that we indeed have taken snapshots.

      [retrieveAllSensorReadout]
      Dim result As ObjectSet = db.[Get](GetType(SensorReadout))
      ListResult(result)
      OUTPUT:
      2
      BMW[Rubens Barrichello/99]/2 : 1152088427384 : 0.2,0.4,0.6
      BMW[Rubens Barrichello/99]/2 : 1152088427384 : 0.1,0.2,0.3


As a prototype for an array, we provide an array of the same type, containing only the values we expect the result to contain.

[retrieveSensorReadoutQBE]
Dim proto As SensorReadout = New SensorReadout(New Double() {0.3, 0.1}, DateTime.MinValue, Nothing)
Dim result As ObjectSet = db.[Get](proto)
ListResult(result)
OUTPUT:
1
BMW[Rubens Barrichello/99]/2 : 1152088427384 : 0.1,0.2,0.3


Note that the actual position of the given elements in the prototype array is irrelevant.

To retrieve a car by its stored sensor readouts, we install a history containing the sought-after values.

[retrieveCarQBE]
Dim protoReadout As SensorReadout = New SensorReadout(New Double() {0.6, 0.2}, DateTime.MinValue, Nothing)
Dim protoHistory As IList = New ArrayList()
protoHistory.Add(protoReadout)
Dim protoCar As Car = New Car(Nothing, protoHistory)
Dim result As ObjectSet = db.[Get](protoCar)
ListResult(result)
OUTPUT:
1
BMW[Rubens Barrichello/99]/2


We can also query for the collections themselves, since they are first class objects.

[retrieveCollections]
Dim result As ObjectSet = db.[Get](New ArrayList())
ListResult(result)
OUTPUT:
2
[]
[BMW[Rubens Barrichello/99]/2 : 1152088427384 : 0.1,0.2,0.3, BMW[Rubens Barrichello/99]/2 : 1152088427384 : 0.2,0.4,0.6]


This doesn't work with arrays, though.

[retrieveArrays]
Dim result As ObjectSet = db.[Get](New Double() {0.6, 0.4})
ListResult(result)
OUTPUT:
0



5.2.2. Native Queries


If we want to use Native Queries to find SensorReadouts with matching values, we simply write this as if we would check every single instance:

Public Class RetrieveSensorReadoutPredicate
Inherits Predicate
    Public Function Match(ByVal candidate As SensorReadout) As Boolean
        Return Array.IndexOf(candidate.Values, 0.3) > - 1 AndAlso Array.IndexOf(candidate.Values, 0.1) > - 1
    End Function
End Class

[retrieveSensorReadoutNative]
Dim results As ObjectSet = db.Query(New RetrieveSensorReadoutPredicate())
ListResult(results)
OUTPUT:
0


And here's how we find Cars with matching readout values:

Public Class RetrieveCarPredicate
Inherits Predicate
    Public Function Match(ByVal car As Car) As Boolean
        For Each sensor As SensorReadout In car.History
            If Array.IndexOf(sensor.Values, 0.3) > - 1 AndAlso Array.IndexOf(sensor.Values, 0.1) > - 1 Then
                Return True
            End If
        Next
        Return False
    End Function
End Class

[retrieveCarNative]
Dim results As ObjectSet = db.Query(New RetrieveCarPredicate())
ListResult(results)
OUTPUT:
1
BMW[Rubens Barrichello/99]/2



5.2.3. Query API


Handling of arrays and collections is analogous to the previous example. First, lets retrieve only the SensorReadouts with specific values:

[retrieveSensorReadoutQuery]
Dim query As Query = db.Query()
query.Constrain(GetType(SensorReadout))
Dim valueQuery As Query = query.Descend("_values")
valueQuery.Constrain(0.3)
valueQuery.Constrain(0.1)
Dim results As ObjectSet = query.Execute()
ListResult(results)
OUTPUT:
1
BMW[Rubens Barrichello/99]/2 : 1152088427384 : 0.1,0.2,0.3


Then let's get some Cars with matching Readout values:

[retrieveCarQuery]
Dim query As Query = db.Query()
query.Constrain(GetType(Car))
Dim historyQuery As Query = query.Descend("_history")
historyQuery.Constrain(GetType(SensorReadout))
Dim valueQuery As Query = historyQuery.Descend("_values")
valueQuery.Constrain(0.3)
valueQuery.Constrain(0.1)
Dim results As ObjectSet = query.Execute()
ListResult(results)
OUTPUT:
1
BMW[Rubens Barrichello/99]/2



5.3. Updating and deleting


This should be familiar, we just have to remember to take care of the update depth.

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


[updateCarPart2]
Dim result As ObjectSet = db.[Get](New Car("BMW", Nothing))
Dim car As Car = DirectCast(result.[Next](), Car)
car.Snapshot()
db.[Set](car)
RetrieveAllSensorReadouts(db)
OUTPUT:
3
BMW[Rubens Barrichello/99]/3 : 1152088428183 : 0.30000000000000004,0.6000000000000001,0.8999999999999999
BMW[Rubens Barrichello/99]/3 : 1152088427384 : 0.2,0.4,0.6
BMW[Rubens Barrichello/99]/3 : 1152088427384 : 0.1,0.2,0.3


There's nothing special about deleting arrays and collections, too.

Deleting an object from a collection is an update, too, of course.

[updateCollection]
Dim query As Query = db.Query()
query.Constrain(GetType(Car))
Dim result As ObjectSet = query.Descend("_history").Execute()
Dim history As IList = DirectCast(result.[Next](), IList)
history.RemoveAt(0)
db.[Set](history)
Dim proto As Car = New Car(Nothing, Nothing)
result = db.[Get](proto)
For Each car As Car In result
    For Each readout As Object In car.History
        Console.WriteLine(readout)
    Next
Next
OUTPUT:
BMW[Rubens Barrichello/99]/2 : 1152088427384 : 0.2,0.4,0.6
BMW[Rubens Barrichello/99]/2 : 1152088428183 : 0.30000000000000004,0.6000000000000001,0.8999999999999999


(This example also shows that with db4o it is quite easy to access object internals we were never meant to see. Please keep this always in mind and be careful.)

We will delete all cars from the database again to prepare for the next chapter.

[deleteAllPart1]
Db4oFactory.Configure().ObjectClass(GetType(Car)).CascadeOnDelete(True)


[deleteAllPart2]
Dim result As ObjectSet = db.[Get](New Car(Nothing, Nothing))
For Each car As Object In result
    db.Delete(car)
Next
Dim readouts As ObjectSet = db.[Get](New SensorReadout(Nothing, DateTime.MinValue, Nothing))
For Each readout As Object In readouts
    db.Delete(readout)
Next



5.4. Conclusion


Ok, collections are just objects. But why did we have to specify the concrete ArrayList type all the way? Was that necessary? How does db4o handle inheritance? We will cover that in the next chapter.


5.5. Full source


Imports System
Imports System.Collections
Imports System.IO
Imports com.db4o
Imports com.db4o.query
Namespace com.db4o.f1.chapter3
    Public Class CollectionsExample
    Inherits Util
        Public Shared Sub Main(ByVal args As String())
            File.Delete(Util.YapFileName)
            Dim db As ObjectContainer = Db4oFactory.OpenFile(Util.YapFileName)
            Try
                StoreFirstCar(db)
                StoreSecondCar(db)
                RetrieveAllSensorReadouts(db)
                RetrieveSensorReadoutQBE(db)
                RetrieveCarQBE(db)
                RetrieveCollections(db)
                RetrieveArrays(db)
                RetrieveSensorReadoutQuery(db)
                RetrieveCarQuery(db)
                db.Close()
                UpdateCarPart1()
                db = Db4oFactory.OpenFile(Util.YapFileName)
                UpdateCarPart2(db)
                UpdateCollection(db)
                db.Close()
                DeleteAllPart1()
                db = Db4oFactory.OpenFile(Util.YapFileName)
                DeleteAllPart2(db)
                RetrieveAllSensorReadouts(db)
            Finally
                db.Close()
            End Try
        End Sub
        Public Shared Sub StoreFirstCar(ByVal db As ObjectContainer)
            Dim car1 As Car = New Car("Ferrari")
            Dim pilot1 As Pilot = New Pilot("Michael Schumacher", 100)
            car1.Pilot = pilot1
            db.[Set](car1)
        End Sub
        Public Shared Sub StoreSecondCar(ByVal db As ObjectContainer)
            Dim pilot2 As Pilot = New Pilot("Rubens Barrichello", 99)
            Dim car2 As Car = New Car("BMW")
            car2.Pilot = pilot2
            car2.Snapshot()
            car2.Snapshot()
            db.[Set](car2)
        End Sub
        Public Shared Sub RetrieveAllSensorReadouts(ByVal db As ObjectContainer)
            Dim result As ObjectSet = db.[Get](GetType(SensorReadout))
            ListResult(result)
        End Sub
        Public Shared Sub RetrieveSensorReadoutQBE(ByVal db As ObjectContainer)
            Dim proto As SensorReadout = New SensorReadout(New Double() {0.3, 0.1}, DateTime.MinValue, Nothing)
            Dim result As ObjectSet = db.[Get](proto)
            ListResult(result)
        End Sub
        Public Shared Sub RetrieveCarQBE(ByVal db As ObjectContainer)
            Dim protoReadout As SensorReadout = New SensorReadout(New Double() {0.6, 0.2}, DateTime.MinValue, Nothing)
            Dim protoHistory As IList = New ArrayList()
            protoHistory.Add(protoReadout)
            Dim protoCar As Car = New Car(Nothing, protoHistory)
            Dim result As ObjectSet = db.[Get](protoCar)
            ListResult(result)
        End Sub
        Public Shared Sub RetrieveCollections(ByVal db As ObjectContainer)
            Dim result As ObjectSet = db.[Get](New ArrayList())
            ListResult(result)
        End Sub
        Public Shared Sub RetrieveArrays(ByVal db As ObjectContainer)
            Dim result As ObjectSet = db.[Get](New Double() {0.6, 0.4})
            ListResult(result)
        End Sub
        Public Shared Sub RetrieveSensorReadoutQuery(ByVal db As ObjectContainer)
            Dim query As Query = db.Query()
            query.Constrain(GetType(SensorReadout))
            Dim valueQuery As Query = query.Descend("_values")
            valueQuery.Constrain(0.3)
            valueQuery.Constrain(0.1)
            Dim results As ObjectSet = query.Execute()
            ListResult(results)
        End Sub
        Public Shared Sub RetrieveCarQuery(ByVal db As ObjectContainer)
            Dim query As Query = db.Query()
            query.Constrain(GetType(Car))
            Dim historyQuery As Query = query.Descend("_history")
            historyQuery.Constrain(GetType(SensorReadout))
            Dim valueQuery As Query = historyQuery.Descend("_values")
            valueQuery.Constrain(0.3)
            valueQuery.Constrain(0.1)
            Dim results As ObjectSet = query.Execute()
            ListResult(results)
        End Sub
        Public Class RetrieveSensorReadoutPredicate
        Inherits Predicate
            Public Function Match(ByVal candidate As SensorReadout) As Boolean
                Return Array.IndexOf(candidate.Values, 0.3) > - 1 AndAlso Array.IndexOf(candidate.Values, 0.1) > - 1
            End Function
        End Class
        Public Shared Sub RetrieveSensorReadoutNative(ByVal db As ObjectContainer)
            Dim results As ObjectSet = db.Query(New RetrieveSensorReadoutPredicate())
            ListResult(results)
        End Sub
        Public Class RetrieveCarPredicate
        Inherits Predicate
            Public Function Match(ByVal car As Car) As Boolean
                For Each sensor As SensorReadout In car.History
                    If Array.IndexOf(sensor.Values, 0.3) > - 1 AndAlso Array.IndexOf(sensor.Values, 0.1) > - 1 Then
                        Return True
                    End If
                Next
                Return False
            End Function
        End Class
        Public Shared Sub RetrieveCarNative(ByVal db As ObjectContainer)
            Dim results As ObjectSet = db.Query(New RetrieveCarPredicate())
            ListResult(results)
        End Sub
        Public Shared Sub UpdateCarPart1()
            Db4oFactory.Configure().ObjectClass(GetType(Car)).CascadeOnUpdate(True)
        End Sub
        Public Shared Sub UpdateCarPart2(ByVal db As ObjectContainer)
            Dim result As ObjectSet = db.[Get](New Car("BMW", Nothing))
            Dim car As Car = DirectCast(result.[Next](), Car)
            car.Snapshot()
            db.[Set](car)
            RetrieveAllSensorReadouts(db)
        End Sub
        Public Shared Sub UpdateCollection(ByVal db As ObjectContainer)
            Dim query As Query = db.Query()
            query.Constrain(GetType(Car))
            Dim result As ObjectSet = query.Descend("_history").Execute()
            Dim history As IList = DirectCast(result.[Next](), IList)
            history.RemoveAt(0)
            db.[Set](history)
            Dim proto As Car = New Car(Nothing, Nothing)
            result = db.[Get](proto)
            For Each car As Car In result
                For Each readout As Object In car.History
                    Console.WriteLine(readout)
                Next
            Next
        End Sub
        Public Shared Sub DeleteAllPart1()
            Db4oFactory.Configure().ObjectClass(GetType(Car)).CascadeOnDelete(True)
        End Sub
        Public Shared Sub DeleteAllPart2(ByVal db As ObjectContainer)
            Dim result As ObjectSet = db.[Get](New Car(Nothing, Nothing))
            For Each car As Object In result
                db.Delete(car)
            Next
            Dim readouts As ObjectSet = db.[Get](New SensorReadout(Nothing, DateTime.MinValue, Nothing))
            For Each readout As Object In readouts
                db.Delete(readout)
            Next
        End Sub
    End Class
End Namespace




--
generated by
Doctor courtesy of db4objects Inc.